Coverage Report

Created: 2026-11-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/server/virtual_servers.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: d3fed13facfdd0b1a3de45cafe9c88488a83a550 $
19
 *
20
 * @file virtual_servers.c
21
 * @brief Defines functions for virtual_server initialisation.
22
 *
23
 * @copyright 2003,2006 The FreeRADIUS server project
24
 * @copyright 2000 Alan DeKok (aland@freeradius.org)
25
 * @copyright 2000 Alan Curry (pacman@world.std.com)
26
 */
27
RCSID("$Id: d3fed13facfdd0b1a3de45cafe9c88488a83a550 $")
28
29
#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
30
#include <freeradius-devel/server/base.h>
31
#include <freeradius-devel/server/process_types.h>
32
33
#include <freeradius-devel/unlang/compile.h>
34
#include <freeradius-devel/unlang/function.h>
35
#include <freeradius-devel/unlang/finally.h>
36
37
#include <freeradius-devel/io/application.h>
38
#include <freeradius-devel/io/master.h>
39
#include <freeradius-devel/io/listen.h>
40
41
#include <freeradius-devel/util/debug.h>
42
43
typedef struct {
44
  module_instance_t   *proto_mi;      //!< The proto_* module for a listen section.
45
  fr_app_t const      *proto_module;      //!< Public interface to the proto_mi.
46
                  ///< cached for convenience.
47
} virtual_server_listen_t;
48
49
struct virtual_server_s {
50
  CONF_SECTION      *server_cs;     //!< The server section.
51
  virtual_server_listen_t   **listeners;      //!< Listeners in this virtual server.
52
53
  module_instance_t   *process_mi;      //!< The process_* module for a virtual server.
54
                  ///< Contains the dictionary used by the virtual
55
                  ///< server and the entry point for the state machine.
56
  fr_process_module_t const *process_module;    //!< Public interface to the process_mi.
57
                  ///< cached for convenience.
58
59
  fr_rb_tree_t      *sections;      //!< List of sections that need to be compiled.
60
61
  fr_log_t      *log;       //!< log destination
62
  char const      *log_name;      //!< name of log destination
63
64
  void        **finally_by_packet_type; //!< Finalise instruction by packet type.
65
  void        *finally_default;   //!< Default finally instruction.
66
};
67
68
static fr_dict_t const *dict_freeradius;
69
70
static fr_dict_attr_t const *attr_auth_type;
71
72
extern fr_dict_autoload_t virtual_server_dict_autoload[];
73
fr_dict_autoload_t virtual_server_dict_autoload[] = {
74
  { .out = &dict_freeradius, .proto = "freeradius" },
75
  DICT_AUTOLOAD_TERMINATOR
76
};
77
78
extern fr_dict_attr_autoload_t virtual_server_dict_attr_autoload[];
79
fr_dict_attr_autoload_t virtual_server_dict_attr_autoload[] = {
80
  { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
81
82
  DICT_AUTOLOAD_TERMINATOR
83
};
84
85
/** List of process modules we've loaded
86
 *
87
 * This is global for all virtual servers.  Must be initialised
88
 * _before_ the configuration is loaded.
89
 */
90
static module_list_t  *process_modules;
91
92
/** List of proto modules we've loaded
93
 *
94
 * This is global for all virtual servers.  Must be initialised
95
 * _before_ the configuration is loaded.
96
 */
97
static module_list_t  *proto_modules;
98
99
/** Top level structure holding all virtual servers
100
 *
101
 */
102
static virtual_server_t **virtual_servers;
103
104
/** CONF_SECTION holding all the virtual servers
105
 *
106
 * Set during the call to virtual_server_bootstrap and used by
107
 * other virtual server functions.
108
 */
109
static CONF_SECTION *virtual_server_root;
110
111
static fr_rb_tree_t *listen_addr_root = NULL;
112
113
static int namespace_on_read(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
114
115
static int namespace_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
116
static int listen_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
117
static int server_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule);
118
119
static const conf_parser_t server_on_read_config[] = {
120
  { FR_CONF_OFFSET_TYPE_FLAGS("namespace", FR_TYPE_VOID, CONF_FLAG_REQUIRED, virtual_server_t, process_mi),
121
      .on_read = namespace_on_read },
122
123
  CONF_PARSER_TERMINATOR
124
};
125
126
const conf_parser_t virtual_servers_on_read_config[] = {
127
  /*
128
   *  Not really ok if it's missing but we want to
129
   *  let logic elsewhere handle the issue.
130
   */
131
  { FR_CONF_POINTER("server", 0, CONF_FLAG_SUBSECTION | CONF_FLAG_OK_MISSING | CONF_FLAG_MULTI, &virtual_servers),
132
        .subcs_size = sizeof(virtual_server_t), .subcs_type = "virtual_server_t",
133
        .subcs = (void const *) server_on_read_config, .name2 = CF_IDENT_ANY,
134
        .on_read = cf_null_on_read },
135
136
  CONF_PARSER_TERMINATOR
137
};
138
139
static const conf_parser_t server_config[] = {
140
  { FR_CONF_OFFSET_TYPE_FLAGS("namespace", FR_TYPE_VOID, CONF_FLAG_REQUIRED, virtual_server_t, process_mi),
141
       .func = namespace_parse },
142
143
  { FR_CONF_OFFSET_TYPE_FLAGS("listen", FR_TYPE_VOID, CONF_FLAG_SUBSECTION | CONF_FLAG_OK_MISSING | CONF_FLAG_MULTI,
144
       virtual_server_t, listeners),
145
       .name2 = CF_IDENT_ANY,
146
       .subcs_size = sizeof(virtual_server_listen_t), .subcs_type = "virtual_server_listen_t",
147
       .func = listen_parse },
148
149
  { FR_CONF_OFFSET("log", virtual_server_t, log_name), },
150
151
  CONF_PARSER_TERMINATOR
152
};
153
154
const conf_parser_t virtual_servers_config[] = {
155
  /*
156
   *  Not really ok if it's missing but we want to
157
   *  let logic elsewhere handle the issue.
158
   */
159
  { FR_CONF_POINTER("server", 0, CONF_FLAG_SUBSECTION | CONF_FLAG_OK_MISSING | CONF_FLAG_MULTI, &virtual_servers),
160
        .subcs_size = sizeof(virtual_server_t), .subcs_type = "virtual_server_t",
161
        .subcs = (void const *) server_config, .name2 = CF_IDENT_ANY,
162
        .func = server_parse },
163
164
  CONF_PARSER_TERMINATOR
165
};
166
167
/** Print all the loaded listener instances
168
 *
169
 */
170
void virtual_server_listen_debug(void)
171
0
{
172
0
  module_list_debug(proto_modules);
173
0
}
174
175
/** Print all the loaded process module instances
176
 *
177
 */
178
void virtual_server_process_debug(void)
179
0
{
180
0
  module_list_debug(process_modules);
181
0
}
182
183
/** Resolve proto data to a module instance
184
 *
185
 * @param[in] data  Pointer to the proto data.
186
 * @return
187
 *  - The module instance for the proto data.
188
 *  - NULL if no data matches.
189
 */
190
module_instance_t *virtual_server_listener_by_data(void const *data)
191
0
{
192
0
  return module_instance_by_data(proto_modules, data);
193
0
}
194
195
/** Generic conf_parser_t func for loading drivers
196
 *
197
 */
198
int virtual_server_listen_transport_parse(TALLOC_CTX *ctx, void *out, void *parent,
199
           CONF_ITEM *ci, conf_parser_t const *rule)
200
0
{
201
0
  conf_parser_t our_rule = *rule;
202
203
0
  our_rule.uctx = &proto_modules;
204
205
0
  return module_submodule_parse(ctx, out, parent, ci, &our_rule);
206
0
}
207
208
/** Parse a "namespace" parameter
209
 *
210
 * We need to load the process module before continuing to parse the virtual server contents
211
 * as we need to know the namespace so that we can resolve attribute names.
212
 *
213
 * We also need the compilation list from the proto module to figure out which sections we
214
 * need to compile.
215
 *
216
 * @param[in] ctx to allocate data in.
217
 * @param[out] out  always NULL
218
 * @param[in] parent  Base structure address.
219
 * @param[in] ci  #CONF_SECTION containing the listen section.
220
 * @param[in] rule  unused.
221
 * @return
222
 *  - 0 on success.
223
 *  - -1 on failure.
224
 */
225
static int namespace_on_read(TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *parent,
226
           CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
227
0
{
228
0
  CONF_PAIR     *cp = cf_item_to_pair(ci);
229
0
  CONF_SECTION      *server_cs = cf_item_to_section(cf_parent(ci));
230
0
  module_instance_t   *mi;
231
0
  char const      *namespace;
232
0
  char        *module_name, *p, *end;
233
0
  char const      *inst_name;
234
0
  fr_process_module_t const *process;
235
236
0
  fr_cond_assert_msg(process_modules,
237
0
         "virtual_servers_init MUST be called before reading virtual server config");
238
239
0
  namespace = cf_pair_value(cp);
240
0
  module_name = talloc_strdup(ctx, namespace);
241
242
  /*
243
   *  Smush all hyphens to underscores for module names
244
   */
245
0
  for (p = module_name, end = module_name + talloc_strlen(module_name);
246
0
       p < end;
247
0
       p++) if (*p == '-') *p = '_';
248
249
0
  if (module_instance_name_from_conf(&inst_name, server_cs) < 0) return -1;
250
251
  /*
252
   *  The module being loaded is the namespace with all '-'
253
   *  transformed to '_'.
254
   *
255
   *  The instance name is the virtual server name.
256
   */
257
0
  mi = module_instance_alloc(process_modules, NULL, DL_MODULE_TYPE_PROCESS,
258
0
           module_name, inst_name,
259
0
           MODULE_INSTANCE_NONE);
260
0
  talloc_free(module_name);
261
0
  if (mi == NULL) {
262
0
  error:
263
0
    cf_log_perr(ci, "Failed loading process module");
264
0
    return -1;
265
0
  }
266
0
  if (unlikely(module_instance_conf_parse(mi, mi->conf) < 0)) {
267
0
    talloc_free(mi);
268
0
    goto error;
269
0
  }
270
271
0
  process = (fr_process_module_t const *)mi->module->exported;
272
0
  if (!*(process->dict)) {
273
0
    cf_log_err(ci, "Process module is invalid - missing namespace dictionary");
274
0
    talloc_free(mi);
275
0
    return -1;
276
0
  }
277
0
  cf_data_add(server_cs, mi, "process_module", false);
278
0
  cf_data_add(server_cs, *(process->dict), "dict", false);
279
280
0
  return 0;
281
0
}
282
283
static inline CC_HINT(always_inline)
284
int add_compile_list(virtual_server_t *vs, CONF_SECTION *cs, virtual_server_compile_t const *compile_list, char const *name)
285
0
{
286
0
  int i;
287
0
  virtual_server_compile_t const *list = compile_list;
288
289
0
  if (!compile_list) return 0;
290
291
0
  for (i = 0; list[i].section; i++) {
292
0
#ifndef NDEBUG
293
    /*
294
     *  We can't have a wildcard for name1.  It MUST be a real name.
295
     *
296
     *  The wildcard was allowed previously for ideas which later didn't turn out.
297
     */
298
0
    if (list[i].section->name1 == CF_IDENT_ANY) {
299
0
      fr_assert(0);
300
0
      continue;
301
0
    }
302
303
0
#endif
304
0
    if (virtual_server_section_register(vs, &list[i]) < 0) {
305
0
      cf_log_err(cs, "Failed registering processing section name %s for %s",
306
0
           list[i].section->name1, name);
307
0
      return -1;
308
0
    }
309
0
  }
310
311
0
  return 0;
312
0
}
313
314
/** dl_open a process_* module
315
 *
316
 * @param[in] ctx to allocate data in.
317
 * @param[out] out  Where to our listen configuration.  Is a #fr_virtual_listen_t structure.
318
 * @param[in] parent  Base structure address.
319
 * @param[in] ci  #CONF_SECTION containing the listen section.
320
 * @param[in] rule  unused.
321
 * @return
322
 *  - 0 on success.
323
 *  - -1 on failure.
324
 */
325
static int namespace_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
326
0
{
327
0
  CONF_PAIR   *cp = cf_item_to_pair(ci);
328
0
  CONF_SECTION    *server_cs = cf_item_to_section(cf_parent(ci));
329
0
  CONF_SECTION    *process_cs;
330
0
  virtual_server_t  *server = talloc_get_type_abort(((uint8_t *) out) - offsetof(virtual_server_t, process_mi), virtual_server_t);
331
0
  char const    *namespace = cf_pair_value(cp);
332
0
  module_instance_t *mi = cf_data_value(cf_data_find(server_cs, module_instance_t, "process_module"));
333
334
  /*
335
   *  We don't have access to virtual_server_t
336
   *  in the onread callback, so we need to do the
337
   *  fixups here.
338
   */
339
0
  server->process_mi = mi;
340
0
  server->process_module = (fr_process_module_t const *)mi->module->exported;
341
342
0
  *(module_instance_t const **)out = mi;
343
344
  /*
345
   *  Enforce that the protocol process configuration is in
346
   *  a subsection named for the protocol.  We don't know if
347
   *  the process code needs this, so we just mark it as
348
   *  parsed, in order to avoid spurious complaints.
349
   */
350
0
  process_cs = cf_section_find(server_cs, namespace, NULL);
351
0
  if (!process_cs) {
352
0
    MEM(process_cs = cf_section_alloc(server_cs, server_cs, namespace, NULL));
353
0
    cf_item_mark_parsed(process_cs);
354
0
  }
355
356
0
  if (module_instance_conf_parse(mi, process_cs) < 0) {
357
0
    cf_log_perr(ci, "Failed bootstrapping process module");
358
0
    cf_data_remove(server_cs, module_instance_t, "process_module");
359
0
    cf_data_remove(server_cs, fr_dict_t, "dict");
360
0
    TALLOC_FREE(server->process_mi);
361
0
    return -1;
362
0
  }
363
364
  /*
365
   *  Pull the list of sections we need to compile out of
366
   *  the process module's public struct.
367
   */
368
0
  return add_compile_list(server, server->process_mi->conf, server->process_module->compile_list, namespace);
369
0
}
370
371
/** dl_open a proto_* module
372
 *
373
 * @param[in] ctx to allocate data in.
374
 * @param[out] out  Where to our listen configuration.  Is a #fr_virtual_listen_t structure.
375
 * @param[in] parent  Base structure address.
376
 * @param[in] ci  #CONF_SECTION containing the listen section.
377
 * @param[in] rule  unused.
378
 * @return
379
 *  - 0 on success.
380
 *  - -1 on failure.
381
 */
382
static int listen_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
383
0
{
384
0
  virtual_server_listen_t *listener = talloc_get_type_abort(out, virtual_server_listen_t); /* Pre-allocated for us */
385
0
  CONF_SECTION    *listener_cs = cf_item_to_section(ci);
386
0
  CONF_SECTION    *server_cs = cf_item_to_section(cf_parent(ci));
387
0
  CONF_PAIR   *namespace = cf_pair_find(server_cs, "namespace");
388
389
0
  CONF_PAIR   *cp;
390
0
  char const    *module, *name2, *p;
391
0
  fr_sbuff_t    *agg;
392
393
0
  module_instance_t *mi;
394
395
0
  fr_cond_assert_msg(proto_modules,
396
0
         "virtual_servers_init MUST be called before reading virtual server config");
397
398
0
  if (!namespace) {
399
0
    cf_log_err(server_cs, "No 'namespace' set for virtual server");
400
0
    cf_log_err(server_cs, "Please add 'namespace = <protocol>' inside of the 'server %s { ... }' section",
401
0
         cf_section_name2(server_cs));
402
0
    return -1;
403
0
  }
404
405
  /*
406
   *  The module we load comes from the 'handler' or 'proto' configuration.  This configuration item
407
   *  allows us to have multi-protocol listen module, such as "detail".
408
   *
409
   *  If there isn't a multi-protocol listen module, then load the one for this namespace, such as
410
   *  "radius".
411
   */
412
0
  cp = cf_pair_find(listener_cs, "handler");
413
0
  if (!cp) cp = cf_pair_find(listener_cs, "proto");
414
0
  if (cp) {
415
0
    module = cf_pair_value(cp);
416
0
    if (!module) {
417
0
      cf_log_err(cp, "Missing value");
418
0
      return -1;
419
0
    }
420
0
  } else {
421
0
    module = cf_pair_value(namespace);
422
0
  }
423
424
  /*
425
   *  The proto modules go into a global tree, so we qualify their name (second name) with the name
426
   *  of the virtual server, followed by the transport, followed by any transport-specific
427
   *  configuration.
428
   */
429
0
  FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 64, MODULE_INSTANCE_LEN_MAX);
430
431
0
  name2 = cf_section_name2(listener_cs);
432
433
  /*
434
   *  A 'listen foo' in this virtual server helps it to be unique.  We load the "radius" module,
435
   *  instance "default.foo".  This naming scheme is a little counter-intuitive, but it is required
436
   *  due to the listen module list being global, and loading the leading module name e.g. "radius".
437
   *
438
   *  Since the virtual server names are unique, we don't have to qualify the listen section names
439
   *  by anything else.
440
   */
441
0
  if (name2) {
442
    /*
443
     *  We do some duplicate checks here, because that gives better errors than if we use the
444
     *  mangled names below.
445
     */
446
0
    if (module_instance_name_valid(name2) < 0) {
447
0
      cf_log_perr(listener_cs, "Invalid name in 'listen %s'", name2);
448
0
      return -1;
449
0
    }
450
451
    /*
452
     *  Load "radius", instance "default.foo".
453
     */
454
0
    if ((fr_sbuff_in_char(agg, '.') < 0) || (fr_sbuff_in_strcpy(agg, name2) < 0)) goto name_too_long;
455
0
  }
456
457
  /*
458
   *  Further qualify the name by transport and port.  This helps it to be more unique.
459
   */
460
0
  cp = cf_pair_find(listener_cs, "transport");
461
0
  if (!cp || ((p = cf_pair_value(cp)) == NULL)) {
462
0
    cf_log_err(listener_cs, "Invalid 'listen' section - No 'transport = ...' definition was found.");
463
0
    return -1;
464
0
  }
465
0
  if ((fr_sbuff_in_char(agg, '.') < 0) || (fr_sbuff_in_strcpy(agg, p) < 0)) {
466
0
  name_too_long:
467
0
    cf_log_err(listener_cs, "Listener name is too long");
468
0
    return -1;
469
0
  }
470
471
0
  cp = cf_pair_find(listener_cs, "port");
472
0
  if (cp && ((p = cf_pair_value(cp)) != NULL)) {
473
0
    if ((fr_sbuff_in_char(agg, '.') < 0) || (fr_sbuff_in_strcpy(agg, p) < 0)) goto name_too_long;
474
0
  }
475
476
0
  if (module_instance_name_valid(fr_sbuff_start(agg)) < 0) {
477
0
    cf_log_perr(listener_cs, "Failed loading listen section.");
478
0
    return -1;
479
0
  }
480
481
0
  mi = module_instance_alloc(proto_modules, NULL, DL_MODULE_TYPE_PROTO, module, fr_sbuff_start(agg), MODULE_INSTANCE_NONE);
482
0
  if (!mi) {
483
0
    cf_log_perr(listener_cs, "Failed creating listen section");
484
0
    return -1;
485
0
  }
486
487
0
  if (unlikely(module_instance_conf_parse(mi, listener_cs) < 0)) {
488
0
    talloc_free(mi);
489
0
    cf_log_perr(listener_cs, "Failed parsing listen section");
490
0
    return -1;
491
0
  }
492
493
0
  listener->proto_mi = mi;
494
0
  listener->proto_module = (fr_app_t const *)listener->proto_mi->module->exported;
495
0
  cf_data_add(listener_cs, mi, "proto_module", false);
496
497
  /*
498
   *  The listener doesn't have to contain a 'type = foo' configuration.  But if it does, there MUST
499
   *  also be a 'recv foo' section.
500
   */
501
0
  for (cp = cf_pair_find(listener_cs, "type");
502
0
       cp != NULL;
503
0
       cp = cf_pair_find_next(listener_cs, cp, "type")) {
504
0
    char const *type = cf_pair_value(cp);
505
506
0
    if (!type) continue;
507
508
0
    if (!cf_section_find(server_cs, "recv", type)) {
509
0
      cf_log_err(cp, "Listener has 'type = %s', but there is no 'recv %s { ... }' section defined.",
510
0
           type, type);
511
0
      return -1;
512
0
    }
513
0
  }
514
515
0
  return 0;
516
0
}
517
518
static fr_cmp_ret_t virtual_server_compile_name_cmp(void const *a, void const *b)
519
0
{
520
0
  virtual_server_compile_t const *sa = a;
521
0
  virtual_server_compile_t const *sb = b;
522
523
0
  return section_name_cmp(sa->section, sb->section);
524
0
}
525
526
/** Callback to validate the server section
527
 *
528
 * @param[in] ctx to allocate data in.
529
 * @param[out] out  Where to our listen configuration.  Is a #virtual_server_t structure.
530
 * @param[in] parent  Base structure address.
531
 * @param[in] ci  #CONF_SECTION containing the listen section.
532
 * @param[in] rule  unused.
533
 * @return
534
 *  - 0 on success.
535
 *  - -1 on failure.
536
 */
537
static int server_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
538
      CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
539
0
{
540
0
  virtual_server_t  *server = talloc_get_type_abort(out, virtual_server_t);
541
0
  CONF_SECTION    *server_cs = cf_item_to_section(ci);
542
0
  CONF_PAIR   *namespace;
543
544
0
  namespace = cf_pair_find(server_cs, "namespace");
545
0
  if (!namespace) {
546
0
    cf_log_err(server_cs, "virtual server %s MUST contain a 'namespace' option",
547
0
         cf_section_name2(server_cs));
548
0
    return -1;
549
0
  }
550
551
0
  MEM(server->sections = fr_rb_alloc(server, virtual_server_compile_name_cmp, NULL));
552
0
  server->server_cs = server_cs;
553
554
  /*
555
   *  Now parse the listeners
556
   */
557
0
  if (cf_section_parse(out, server, server_cs) < 0) return -1;
558
559
  /*
560
   *  And cache this struct for later referencing.
561
   */
562
0
  cf_data_add(server_cs, server, NULL, false);
563
564
0
  return 0;
565
0
}
566
567
/** Return the namespace for the named virtual server
568
 *
569
 * @param[in] virtual_server  to look for namespace in.
570
 * @return
571
 *  - NULL on error.
572
 *  - Namespace on success.
573
 */
574
fr_dict_t const *virtual_server_dict_by_name(char const *virtual_server)
575
0
{
576
0
  virtual_server_t const *vs;
577
578
0
  vs = virtual_server_find(virtual_server);
579
0
  if (!vs) return NULL;
580
581
0
  return virtual_server_dict_by_cs(vs->server_cs);
582
0
}
583
584
/** Return the namespace for specified CONF_SECTION
585
 *
586
 * @param[in] cs    to look for namespace in.
587
 * @return
588
 *  - NULL on error.
589
 *  - Namespace on success.
590
 */
591
fr_dict_t const *virtual_server_dict_by_cs(CONF_SECTION const *cs)
592
0
{
593
0
  CONF_DATA const *cd;
594
0
  fr_dict_t *dict;
595
596
0
  cd = cf_data_find(cs, fr_dict_t, "dict");
597
0
  if (!cd) return NULL;
598
599
0
  dict = cf_data_value(cd);
600
0
  (void) talloc_get_type_abort(dict, fr_dict_t);
601
602
0
  return dict;
603
0
}
604
605
/** Return the namespace for a given virtual server specified by a CONF_ITEM within the virtual server
606
 *
607
 * @param[in] ci    to look for namespace in.
608
 * @return
609
 *  - NULL on error.
610
 *  - Namespace on success.
611
 */
612
fr_dict_t const *virtual_server_dict_by_child_ci(CONF_ITEM const *ci)
613
0
{
614
0
  CONF_DATA const *cd;
615
0
  fr_dict_t *dict;
616
617
0
  cd = cf_data_find_in_parent(ci, fr_dict_t, "dict");
618
0
  if (!cd) return NULL;
619
620
0
  dict = cf_data_value(cd);
621
0
  (void) talloc_get_type_abort(dict, fr_dict_t);
622
623
0
  return dict;
624
0
}
625
626
/** Verify that a given virtual_server exists and is of a particular namespace
627
 *
628
 * Mostly used by modules to check virtual servers specified by their configs.
629
 *
630
 * @param[out] out    we found. May be NULL if just checking for existence.
631
 * @param[in] virtual_server  to check.
632
 * @param[in] namespace   the virtual server must belong to.
633
 * @param[in] ci    to log errors against. May be NULL if caller
634
 *        doesn't want errors logged.
635
 * @return
636
 *  - 0 on success.
637
 *  - -1 if no virtual server could be found.
638
 *  - -2 if virtual server is not of the correct namespace.
639
 */
640
int virtual_server_has_namespace(CONF_SECTION **out,
641
         char const *virtual_server, fr_dict_t const *namespace, CONF_ITEM *ci)
642
0
{
643
0
  virtual_server_t const  *vs;
644
0
  CONF_SECTION    *server_cs;
645
0
  fr_dict_t const   *dict;
646
647
0
  if (out) *out = NULL;
648
649
0
  vs = virtual_server_find(virtual_server);
650
0
  if (!vs) {
651
0
    if (ci) cf_log_err(ci, "Can't find virtual server \"%s\"", virtual_server);
652
0
    return -1;
653
0
  }
654
0
  server_cs = virtual_server_cs(vs);
655
656
0
  dict = virtual_server_dict_by_name(virtual_server);
657
0
  if (!dict) {
658
    /*
659
     *  Not sure this is even a valid state?
660
     */
661
0
    if (ci) cf_log_err(ci, "No namespace found in virtual server \"%s\"", virtual_server);
662
0
    return -2;
663
0
  }
664
665
0
  if (dict != namespace) {
666
0
    if (ci) {
667
0
      cf_log_err(ci,
668
0
           "Expected virtual server \"%s\" to be of namespace \"%s\", got namespace \"%s\"",
669
0
           virtual_server, fr_dict_root(namespace)->name, fr_dict_root(dict)->name);
670
0
    }
671
0
    return -2;
672
0
  }
673
674
0
  if (out) *out = server_cs;
675
676
0
  return 0;
677
0
}
678
679
/*
680
 *  If we pushed a log destination, we need to pop it.
681
 */
682
static unlang_action_t server_remove_log_destination(UNUSED unlang_result_t *p_result,
683
                 request_t *request, void *uctx)
684
0
{
685
0
  virtual_server_t *server = uctx;
686
687
0
  request_log_prepend(request, server->log, L_DBG_LVL_DISABLE);
688
689
0
  return UNLANG_ACTION_CALCULATE_RESULT;
690
0
}
691
692
static void server_signal_remove_log_destination(request_t *request, UNUSED fr_signal_t action, void *uctx)
693
0
{
694
0
  virtual_server_t *server = uctx;
695
696
0
  request_log_prepend(request, server->log, L_DBG_LVL_DISABLE);
697
0
}
698
699
/** Push a finally section onto the stack
700
 *
701
 * The finally instruction cannot be cancelled and will always execute as the stack is unwound.
702
 *
703
 * @param[in] request   request to push the finally section onto.
704
 * @param[in] vs    virtual server to push the finally section for.
705
 * @param[in,out] top_frame mutate the top frame value to indicate that future
706
 *        pushes should be subframes.
707
 * @return
708
 *  - 0 on success.
709
 *  - -1 on failure.
710
 */
711
static inline CC_HINT(always_inline) int virtual_server_push_finally(request_t *request, virtual_server_t const *vs, bool *top_frame)
712
0
{
713
  /*
714
   *  Don't bother finding the packet type unless there
715
   *  are finally sections registered.
716
   */
717
0
  if (vs->finally_by_packet_type) {
718
0
    fr_pair_t *vp = fr_pair_find_by_da(&request->request_pairs, NULL,
719
0
               *(vs->process_module->packet_type));
720
0
    fr_value_box_t  key;
721
0
    void    *instruction;
722
723
0
    if (!vp) goto check_default; /* No packet type found, still allow default finally section */
724
725
0
    if (fr_value_box_cast(NULL, &key, FR_TYPE_UINT16, NULL, &vp->data) < 0) return -1;
726
727
0
    if (key.vb_uint16 >= talloc_array_length(vs->finally_by_packet_type) ||
728
0
        !(instruction = vs->finally_by_packet_type[key.vb_uint16])) goto check_default;
729
730
0
    if (unlikely(unlang_finally_push_instruction(request, instruction,
731
0
                   fr_time_delta_from_sec(5), *top_frame) < 0)) return -1;
732
733
0
    *top_frame = UNLANG_SUB_FRAME; /* switch to SUB_FRAME after the first instruction */
734
735
0
    return 0;
736
0
  }
737
738
0
check_default:
739
0
  if (vs->finally_default) {
740
0
    if (unlikely(unlang_finally_push_instruction(request, vs->finally_default,
741
0
                   fr_time_delta_from_sec(5), *top_frame) < 0)) return -1;
742
743
0
    *top_frame = UNLANG_SUB_FRAME; /* switch to SUB_FRAME after the first instruction */
744
0
  }
745
746
0
  return 0;
747
0
}
748
749
/** Set the request processing function.
750
 *
751
 *  Short-term hack
752
 */
753
unlang_action_t virtual_server_push(unlang_result_t *p_result, request_t *request, virtual_server_t const *vs, bool top_frame)
754
0
{
755
  /*
756
   *  Add a log destination specific to this virtual server.
757
   *
758
   *  If we add a log destination, make sure to remove it when we walk back up the stack.
759
   *  But ONLY if we're not at the top of the stack.
760
   *
761
   *  When a brand new request comes in, it has a "call" frame pushed, and then this function is
762
   *  called.  So if we're at the top of the stack, we don't need to pop any logging function,
763
   *  because the request will die immediately after the top "call" frame is popped.
764
   *
765
   *  However, if we're being reached from a "call" frame in the middle of the stack, then
766
   *  we do have to pop the log destination when we return.
767
   */
768
0
  if (vs->log) {
769
0
    request_log_prepend(request, vs->log, fr_debug_lvl);
770
771
0
    if (unlang_interpret_stack_depth(request) > 1) {
772
0
      unlang_action_t action;
773
774
0
      action = unlang_function_push_with_result(unlang_interpret_result(request),  /* transparent */
775
0
                  request,
776
0
                  NULL,         /* don't call it immediately */
777
0
                  server_remove_log_destination,  /* but when we pop the frame */
778
0
                  server_signal_remove_log_destination, FR_SIGNAL_ALLOW(FR_SIGNAL_CANCEL),
779
0
                  top_frame,
780
0
                  UNCONST(void *, vs));
781
0
      if (action != UNLANG_ACTION_PUSHED_CHILD) return action;
782
783
0
      top_frame = UNLANG_SUB_FRAME; /* switch to SUB_FRAME after the first instruction */
784
0
    }
785
0
  }
786
787
  /*
788
   *  Push an uncancellable finally instruction to the stack.
789
   */
790
0
  if (virtual_server_push_finally(request, vs, &top_frame) < 0) return UNLANG_ACTION_FAIL;
791
792
  /*
793
   *  Bootstrap the stack with a module instance.
794
   */
795
0
  if (unlang_module_push(p_result, request, vs->process_mi,
796
0
             vs->process_module->process, top_frame) < 0) return UNLANG_ACTION_FAIL;
797
798
0
  return UNLANG_ACTION_PUSHED_CHILD;
799
0
}
800
801
static int cmd_show_server_list(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info)
802
0
{
803
0
  size_t i, server_cnt = virtual_servers ? talloc_array_length(virtual_servers) : 0;
804
805
0
  if (!server_cnt) return 0;
806
807
0
  for (i = 0; i < server_cnt; i++) {
808
0
    fprintf(fp, "%-30snamespace = %s\n", cf_section_name2(virtual_servers[i]->server_cs),
809
0
      fr_dict_root(*(virtual_servers[i]->process_module->dict))->name);
810
0
  }
811
812
0
  return 0;
813
0
}
814
815
static fr_cmd_table_t cmd_table[] = {
816
  {
817
    .parent = "show",
818
    .name = "server",
819
    .help = "Show virtual server settings.",
820
    .read_only = true,
821
  },
822
823
  {
824
    .parent = "show server",
825
    .name = "list",
826
    .func = cmd_show_server_list,
827
    .help = "Show the list of virtual servers loaded in the server.",
828
    .read_only = true,
829
  },
830
831
  CMD_TABLE_END
832
833
};
834
835
/** Compare listeners by app_io_addr
836
 *
837
 *  Only works for IP addresses, and will blow up on file names
838
 */
839
static fr_cmp_ret_t listen_addr_cmp(void const *one, void const *two)
840
0
{
841
0
  fr_listen_instance_t const *a = one;
842
0
  fr_listen_instance_t const *b = two;
843
0
  fr_ipaddr_t aip, bip;
844
0
  int ret;
845
846
  /*
847
   *  The caller must ensure that the address field is set.
848
   */
849
0
  if (!a->app_io_addr && !b->app_io_addr) return CMP_EQ;
850
0
  if (!a->app_io_addr && b->app_io_addr) return CMP_LT;
851
0
  if (a->app_io_addr && !b->app_io_addr) return CMP_GT;
852
853
  /*
854
   *  Address family
855
   */
856
0
  CMP_RETURN(a, b, app_io_addr->af);
857
858
0
  fr_assert((a->app_io_addr->af == AF_INET) || ((a->app_io_addr->af == AF_INET6)));
859
860
  /*
861
   *  UDP vs TCP
862
   */
863
0
  CMP_RETURN(a, b, app_io_addr->type);
864
865
  /*
866
   *  Check ports.
867
   */
868
0
  CMP_RETURN(a, b, app_io_addr->inet.src_port);
869
870
  /*
871
   *  Don't call fr_ipaddr_cmp(), as we need to do our own
872
   *  checks here.  We have various wildcard checks which
873
   *  aren't globally applicable.
874
   */
875
876
  /*
877
   *  Different address families.
878
   */
879
0
  CMP_RETURN(a, b, app_io_addr->inet.src_ipaddr.af);
880
881
  /*
882
   *  If both are bound to interfaces, AND the interfaces
883
   *  are different, then there is no conflict.
884
   */
885
0
  if (a->app_io_addr->inet.src_ipaddr.scope_id && b->app_io_addr->inet.src_ipaddr.scope_id) {
886
0
    CMP_RETURN(a, b, app_io_addr->inet.src_ipaddr.scope_id);
887
0
  }
888
889
0
  ret = a->app_io_addr->inet.src_ipaddr.prefix - b->app_io_addr->inet.src_ipaddr.prefix;
890
0
  aip = a->app_io_addr->inet.src_ipaddr;
891
0
  bip = b->app_io_addr->inet.src_ipaddr;
892
893
  /*
894
   *  Mask out the longer prefix to match the shorter
895
   *  prefix.
896
   */
897
0
  if (ret < 0) {
898
0
    fr_ipaddr_mask(&bip, a->app_io_addr->inet.src_ipaddr.prefix);
899
900
0
  } else if (ret > 0) {
901
0
    fr_ipaddr_mask(&aip, b->app_io_addr->inet.src_ipaddr.prefix);
902
903
0
  }
904
905
0
  return fr_ipaddr_cmp(&aip, &bip);
906
0
}
907
908
/** See if another global listener is using a particular IP / port
909
 *
910
 */
911
fr_listen_instance_t *listen_find_any(fr_listen_instance_t *li)
912
0
{
913
0
  fr_listen_instance_t *found;
914
915
0
  if (!listen_addr_root) return NULL;
916
917
0
  fr_rb_find((void **)&found, listen_addr_root, li);
918
919
0
  return found;
920
0
}
921
922
923
/**  Record that we're listening on a particular IP / port
924
 *
925
 */
926
bool listen_record(fr_listen_instance_t *li)
927
0
{
928
0
  if (!listen_addr_root) return false;
929
930
0
  if (!li->app_io_addr) return true;
931
932
0
  if (listen_find_any(li) != NULL) return false;
933
934
0
  return fr_rb_insert(listen_addr_root, li) == 0;
935
0
}
936
937
/** Return the configuration section for a virtual server
938
 *
939
 * @param[in] vs to return conf section for
940
 * @return
941
 *  - The CONF_SECTION of the virtual server.
942
 */
943
CONF_SECTION *virtual_server_cs(virtual_server_t const *vs)
944
0
{
945
0
  return vs->server_cs;
946
0
}
947
948
/** Resolve a CONF_SECTION to a virtual server
949
 *
950
 */
951
virtual_server_t const *virtual_server_from_cs(CONF_SECTION const *server_cs)
952
0
{
953
0
  virtual_server_t *vs;
954
955
0
  vs = cf_data_value(cf_data_find(server_cs, virtual_server_t, NULL));
956
0
  if (!vs) {
957
0
    cf_log_err(server_cs, "server_cs does not contain virtual server data");
958
0
    return NULL;
959
0
  }
960
961
0
  return vs;
962
0
}
963
964
/** Return virtual server matching the specified name
965
 *
966
 * @note May be called in bootstrap or instantiate as all servers should be present.
967
 *
968
 * @param[in] name  of virtual server.
969
 * @return
970
 *  - NULL if no virtual server was found.
971
 *  - The CONF_SECTION of the named virtual server.
972
 */
973
virtual_server_t const *virtual_server_find(char const *name)
974
0
{
975
0
  CONF_SECTION *server_cs = cf_section_find(virtual_server_root, "server", name);
976
0
  CONF_DATA const *cd;
977
978
0
  if (unlikely(server_cs == NULL)) return NULL;
979
980
0
  cd = cf_data_find(server_cs, virtual_server_t, NULL);
981
0
  if (unlikely(cd == NULL)) return NULL;
982
983
0
  return cf_data_value(cd);
984
0
}
985
986
/** Find a virtual server using one of its sections
987
 *
988
 * @param[in] ci  to find parent virtual server for.
989
 * @return
990
 *  - The virtual server section on success.
991
 *  - NULL if the child isn't associated with any virtual server section.
992
 */
993
virtual_server_t const *virtual_server_by_child(CONF_ITEM const *ci)
994
0
{
995
0
  CONF_SECTION *cs;
996
0
  CONF_DATA const *cd;
997
998
0
  cs = cf_section_find_parent(ci, "server", CF_IDENT_ANY);
999
0
  if (unlikely(!cs)) {
1000
0
    cf_log_err(ci, "Child section is not associated with a virtual server");
1001
0
    return NULL;
1002
0
  }
1003
1004
0
  cd = cf_data_find(cs, virtual_server_t, NULL);
1005
0
  if (unlikely(!cd)) {
1006
0
    cf_log_err(ci, "Virtual server section missing virtual_server_t data");
1007
0
    return NULL;
1008
0
  }
1009
1010
0
  return cf_data_value(cd);
1011
0
}
1012
1013
/** Return the packet type attribute for a virtual server specified by a config section
1014
 *
1015
 * @param[in] server_cs   to look for packet type attribute in.
1016
 * @return
1017
 *  - NULL on error.
1018
 *  - packet type dict attr on success.
1019
 */
1020
fr_dict_attr_t const *virtual_server_packet_type_by_cs(CONF_SECTION const *server_cs)
1021
0
{
1022
0
  virtual_server_t const *vs = virtual_server_from_cs(server_cs);
1023
1024
0
  if (unlikely(!vs || !vs->process_module || !vs->process_module->packet_type)) return NULL;
1025
0
  return *vs->process_module->packet_type;
1026
0
}
1027
1028
/** Wrapper for the config parser to allow pass1 resolution of virtual servers
1029
 *
1030
 */
1031
int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
1032
          CONF_ITEM *ci, conf_parser_t const *rule)
1033
0
{
1034
0
  virtual_server_t const *vs;
1035
0
  virtual_server_cf_parse_uctx_t const *uctx = rule->uctx;
1036
1037
0
  vs = virtual_server_find(cf_pair_value(cf_item_to_pair(ci)));
1038
0
  if (!vs) {
1039
0
    cf_log_err(ci, "virtual-server \"%s\" not found", cf_pair_value(cf_item_to_pair(ci)));
1040
0
    return -1;
1041
0
  }
1042
1043
  /*
1044
   *  Validation checks
1045
   */
1046
0
  if (uctx) {
1047
    /*
1048
     *  Check the module name
1049
     *
1050
     *  FIXME: ...at some point in the distance future.  Names
1051
     *  are icky, we should compare based on dl_module_t, but
1052
     *  ordering issues make this difficult currently.
1053
     */
1054
0
    if (uctx->process_module_name) {
1055
      /* catch users doing stupid things */
1056
0
      if (strcmp(uctx->process_module_name, vs->process_mi->module->name) != 0) {
1057
0
        cf_log_err(ci, "virtual server \"%s\" must be of type \"%s\", "
1058
0
             "got type \"%s\"",
1059
0
             cf_pair_value(cf_item_to_pair(ci)),
1060
0
             uctx->process_module_name, vs->process_mi->module->name);
1061
0
        return -1;
1062
0
      }
1063
0
    }
1064
1065
    /*
1066
     *  It's theoretically possible for the same module to be used
1067
     *  with multiple namespaces, so we need this check too.
1068
     */
1069
0
    if (uctx->required_dict) {
1070
0
      fr_dict_t *required_dict = *uctx->required_dict;
1071
1072
0
      if (!fr_cond_assert_msg(required_dict != NULL,
1073
0
            "dict not resolved before virtual server reference")) {
1074
0
        return -1;
1075
0
      }
1076
1077
0
      if (required_dict != *vs->process_module->dict) {
1078
0
        cf_log_err(ci, "virtual server \"%s\" must use namespace \"%s\", "
1079
0
             "got namespace \"%s\"",
1080
0
             cf_pair_value(cf_item_to_pair(ci)),
1081
0
             fr_dict_root(required_dict)->name,
1082
0
             fr_dict_root(*vs->process_module->dict)->name);
1083
0
        return -1;
1084
0
      }
1085
0
    }
1086
0
  }
1087
1088
0
  *((virtual_server_t const **)out) = vs;
1089
1090
0
  return 0;
1091
0
}
1092
1093
static inline CC_HINT(always_inline) int virtual_server_compile_finally_sections(virtual_server_t *vs, tmpl_rules_t const *rules, int *found)
1094
0
{
1095
0
  static unlang_mod_actions_t const mod_actions_finally = {
1096
0
    .actions = {
1097
0
      [RLM_MODULE_REJECT] = MOD_PRIORITY_3,
1098
0
      [RLM_MODULE_FAIL] = MOD_PRIORITY_1,
1099
0
      [RLM_MODULE_OK]   = MOD_PRIORITY_4,
1100
0
      [RLM_MODULE_HANDLED]  = MOD_ACTION_RETURN,
1101
0
      [RLM_MODULE_INVALID]  = MOD_PRIORITY_2,
1102
0
      [RLM_MODULE_DISALLOW] = MOD_PRIORITY_5,
1103
0
      [RLM_MODULE_NOTFOUND] = MOD_PRIORITY_6,
1104
0
      [RLM_MODULE_NOOP] = MOD_PRIORITY_8,
1105
0
      [RLM_MODULE_UPDATED]  = MOD_PRIORITY_7
1106
0
    },
1107
0
    .retry = RETRY_INIT,
1108
0
  };
1109
1110
0
  fr_dict_attr_t const  *da;
1111
0
  fr_dict_attr_t const  **da_p = vs->process_module->packet_type;
1112
0
  CONF_SECTION    *subcs;
1113
1114
0
  if (!da_p || !*da_p) {
1115
0
    subcs = cf_section_find(vs->server_cs, "finally", CF_IDENT_ANY);
1116
0
    if (!subcs) return 0;
1117
1118
0
    cf_log_err(subcs, "Invalid 'finally' section - virtual server does not define a 'packet_type'");
1119
0
    return -1;
1120
0
  }
1121
1122
0
  da = *da_p;
1123
1124
  /*
1125
   *  Iterate over all the finally sections, trying to resolve
1126
   *  the name2 to packet types.
1127
   */
1128
0
  for (subcs = cf_section_find(vs->server_cs, "finally", CF_IDENT_ANY);
1129
0
       subcs;
1130
0
       subcs = cf_section_find_next(vs->server_cs, subcs, "finally", CF_IDENT_ANY)) {
1131
0
    char const      *packet_type = cf_section_name2(subcs);
1132
0
    fr_dict_enum_value_t const  *ev;
1133
0
    fr_value_box_t      key;
1134
0
    int       ret;
1135
0
    void        *instruction;
1136
1137
0
    if (!packet_type) {
1138
0
      if (vs->finally_default) {
1139
0
        cf_log_err(subcs, "Duplicate 'finally { ... }' section");
1140
0
        return -1;
1141
0
      }
1142
1143
0
      ret = unlang_compile(vs, subcs, &mod_actions_finally, rules, &instruction);
1144
0
      if (ret < 0) return -1;
1145
1146
0
      vs->finally_default = instruction;
1147
0
      (*found)++;
1148
1149
0
      continue;
1150
0
    }
1151
1152
    /*
1153
     *  FIXME: This would allow response packet types too
1154
     *  We don't have anything that lists request/response
1155
     *  types, so we can't check that here.
1156
     */
1157
0
    ev = fr_dict_enum_by_name(da, packet_type, talloc_strlen(packet_type));
1158
0
    if (!ev) {
1159
0
      cf_log_err(subcs, "Invalid 'finally %s { ... }' section, "
1160
0
          "does not match any Packet-Type value", packet_type);
1161
0
      return -1;
1162
0
    }
1163
1164
    /*
1165
     *  This is... unlikely, as protocols usually use small
1166
     *  packet types.
1167
     */
1168
0
    if (!fr_type_is_integer_except_bool(ev->value->type)) {
1169
0
    forbid:
1170
0
      fr_assert(da);
1171
0
      cf_log_err(subcs, "'finally %s { ... }' section, "
1172
0
           "not supported for this protocol.  %s is a %s", packet_type,
1173
0
           da->name, fr_type_to_str(ev->value->type));
1174
0
      return -1;
1175
0
    }
1176
1177
0
    if (fr_value_box_cast(NULL, &key, FR_TYPE_UINT16, NULL, ev->value) < 0) {
1178
0
      goto forbid;
1179
0
    }
1180
1181
0
    if (key.vb_uint16 >= talloc_array_length(vs->finally_by_packet_type)) {
1182
0
      MEM(vs->finally_by_packet_type = talloc_realloc_zero(vs, vs->finally_by_packet_type,
1183
0
                       void *, key.vb_uint16 + 1));
1184
0
    }
1185
1186
0
    if (vs->finally_by_packet_type[key.vb_uint16]) {
1187
0
      cf_log_err(subcs, "Duplicate 'finally %s { ... }' section", packet_type);
1188
0
      return -1;
1189
0
    }
1190
1191
0
    ret = unlang_compile(vs, subcs, &mod_actions_finally, rules, &instruction);
1192
0
    if (ret < 0) return -1;
1193
1194
0
    vs->finally_by_packet_type[key.vb_uint16] = instruction;
1195
1196
0
    (*found)++;
1197
0
  }
1198
1199
0
  return 0;
1200
0
}
1201
1202
/*
1203
 *  Check for 'send FOO' and 'recv BAR' which are unused.
1204
 */
1205
static bool virtual_server_warn_unused(CONF_SECTION *server, virtual_server_compile_t const *list)
1206
0
{
1207
0
  bool fail = false;
1208
1209
0
  cf_section_foreach(server, subcs) {
1210
0
    char const *name, *name2;
1211
1212
0
    if (cf_item_is_parsed(subcs)) continue;
1213
1214
0
    name = cf_section_name1(subcs);
1215
1216
    /*
1217
     *  Allow them to "comment out" an entire block by prefixing the name with "-", ala
1218
     *  "-sql".
1219
     */
1220
0
    if (*name == '-') continue;
1221
1222
    /*
1223
     *  Local clients are parsed by the listener after the virtual server is bootstrapped.  So
1224
     *  we just ignore them here.
1225
     */
1226
0
    if (strcmp(name, "client") == 0) continue;
1227
1228
0
    name2 = cf_section_name2(subcs);
1229
1230
    /*
1231
     *  When checking the configuration, it is an error to have an unused "send FOO" or "recv
1232
     *  BAR" section.
1233
     */
1234
0
    if (check_config && ((strcmp(name, "recv") == 0) || (strcmp(name, "send") == 0))) {
1235
0
      if (!name2) {
1236
0
        cf_log_err(subcs, "Unused processing section' %s {'", name);
1237
0
        cf_log_err(subcs, "If this is intentional, please rename it to '-%s { ...'", name);
1238
0
      } else {
1239
0
        cf_log_err(subcs, "Unused processing section '%s %s {'", name, name2);
1240
0
        cf_log_err(subcs, "If this is intentional, please rename it to '-%s %s { ...'",
1241
0
             name, name2);
1242
0
      }
1243
1244
0
      fail = true;
1245
0
      continue;
1246
0
    }
1247
1248
    /*
1249
     *  Print warnings if it's unused.  If there's an issue with case sensitivity, then that's
1250
     *  an error, even if we're not running check_config.
1251
     */
1252
0
    name2 = cf_section_name2(subcs);
1253
0
    if (!name2) {
1254
0
      cf_log_warn(subcs, "Ignoring '%s {' - it is unused", name);
1255
1256
0
    } else if (list) {
1257
0
      int i;
1258
0
      const char *realname = NULL;
1259
1260
      /*
1261
       *  See if it's a case-sensitive issue.
1262
       *
1263
       *  The dictionaries are case insensitive.  The configuration files are
1264
       *  case sensitive.
1265
       */
1266
0
      for (i = 0; list[i].section; i++) {
1267
0
        if (list[i].section->name2 == CF_IDENT_ANY) continue;
1268
1269
0
        if (strcasecmp(list[i].section->name2, name2) == 0) {
1270
0
          realname = list[i].section->name2;
1271
0
          break;
1272
0
        }
1273
0
      }
1274
1275
0
      if (realname) {
1276
0
        cf_log_err(subcs, "Unused processing section '%s %s {'", name, name2);
1277
0
        cf_log_err(subcs, "Do you mean '%s %s { ...' ? ", name, realname);
1278
0
        fail = true;
1279
0
        break;
1280
0
      }
1281
1282
0
      cf_log_warn(subcs, "Ignoring %s %s { - it is unused", name, name2);
1283
0
    }
1284
0
  }
1285
1286
0
  return fail;
1287
0
}
1288
1289
/** Compile sections for a virtual server.
1290
 *
1291
 *  When the "proto_foo" module calls fr_app_process_instantiate(), it
1292
 *  loads the compile list from the #fr_app_worker_t, and calls this
1293
 *  function.
1294
 *
1295
 *  This function walks down the registration table, compiling each
1296
 *  named section.
1297
 *
1298
 * @param[in] vs  to compile sections for.
1299
 * @param[in] rules to apply for pass1.
1300
 */
1301
static int virtual_server_compile_sections(virtual_server_t *vs, tmpl_rules_t const *rules)
1302
0
{
1303
0
  virtual_server_compile_t const  *list = vs->process_module->compile_list;
1304
0
  void        *instance = vs->process_mi->data;
1305
0
  CONF_SECTION      *server = vs->server_cs;
1306
0
  int       i, found;
1307
0
  bool        fail;
1308
0
  CONF_SECTION      *subcs = NULL;
1309
0
  char const      *name, *name2;
1310
1311
0
  found = 0;
1312
1313
  /*
1314
   *  Complain about v3 things being used in v4.
1315
   *
1316
   *  Don't complain when running in normal mode, because the server will just ignore the new
1317
   *  sections.  But the check_config stuff is generally run before the service starts, and we
1318
   *  definitely want to tell people when running in debug mode.
1319
   */
1320
0
  if (check_config || DEBUG_ENABLED) {
1321
0
    fail = false;
1322
1323
0
    while ((subcs = cf_section_next(server, subcs)) != NULL) {
1324
0
      if (cf_section_name2(subcs) != NULL) continue;
1325
1326
0
      name = cf_section_name1(subcs);
1327
0
      if ((strcmp(name, "authorize") == 0) ||
1328
0
          (strcmp(name, "authenticate") == 0) ||
1329
0
          (strcmp(name, "post-auth") == 0) ||
1330
0
          (strcmp(name, "preacct") == 0) ||
1331
0
          (strcmp(name, "accounting") == 0) ||
1332
0
          (strcmp(name, "pre-proxy") == 0) ||
1333
0
          (strcmp(name, "post-proxy") == 0)) {
1334
0
        cf_log_err(subcs, "Version 3 processing section '%s' is not valid in version 4.",
1335
0
             name);
1336
0
        fail = true;
1337
0
      }
1338
0
    }
1339
1340
    /*
1341
     *  Complain about _all_ of the sections, and not just the first one.
1342
     */
1343
0
    if (fail) return -1;
1344
0
  }
1345
1346
  /*
1347
   *  The sections are in trees, so this isn't as bad as it
1348
   *  looks.  It's not O(n^2), but O(n logn).  But it could
1349
   *  still be improved.
1350
   */
1351
0
  for (i = 0; list[i].section; i++) {
1352
0
    int rcode;
1353
0
    CONF_SECTION *bad;
1354
1355
    /*
1356
     *  We are looking for a specific subsection.
1357
     *  Warn if it isn't found, or compile it if
1358
     *  found.
1359
     */
1360
0
    if (list[i].section->name2 != CF_IDENT_ANY) {
1361
0
      void *instruction = NULL;
1362
1363
0
      subcs = cf_section_find(server, list[i].section->name1, list[i].section->name2);
1364
0
      if (!subcs) {
1365
0
        DEBUG3("Warning: Skipping %s %s { ... } as it was not found.",
1366
0
               list[i].section->name1, list[i].section->name2);
1367
        /*
1368
         *  Initialise CONF_SECTION pointer for missing section
1369
         */
1370
0
        if ((instance) && !list[i].dont_cache) {
1371
0
          *(CONF_SECTION **) (((uint8_t *) instance) + list[i].offset) = NULL;
1372
0
        }
1373
0
        continue;
1374
0
      }
1375
1376
      /*
1377
       *  Duplicate sections are forbidden.
1378
       */
1379
0
      bad = cf_section_find_next(server, subcs, list[i].section->name1, list[i].section->name2);
1380
0
      if (bad) {
1381
0
      forbidden:
1382
0
        cf_log_err(bad, "Duplicate sections are forbidden.");
1383
0
        cf_log_err(subcs, "Previous definition occurs here.");
1384
0
        return -1;
1385
0
      }
1386
1387
0
      rcode = unlang_compile(vs, subcs, list[i].actions, rules, &instruction);
1388
0
      if (rcode < 0) return -1;
1389
1390
      /*
1391
       *  Cache the CONF_SECTION which was found.
1392
       */
1393
0
      if (instance) {
1394
0
        if (!list[i].dont_cache) {
1395
0
          *(CONF_SECTION **) (((uint8_t *) instance) + list[i].offset) = subcs;
1396
0
        }
1397
0
        if (list[i].instruction > 0) {
1398
0
          *(void **) (((uint8_t *) instance) + list[i].instruction) = instruction;
1399
0
        }
1400
0
      }
1401
1402
0
      found++;
1403
0
      continue;
1404
0
    }
1405
1406
    /*
1407
     *  Reset this so that we start from the beginning
1408
     *  again, instead of starting from the last "send
1409
     *  foo" block.
1410
     */
1411
0
    subcs = NULL;
1412
1413
    /*
1414
     *  Find all subsections with the given first name
1415
     *  and compile them.
1416
     */
1417
0
    while ((subcs = cf_section_find_next(server, subcs, list[i].section->name1, CF_IDENT_ANY))) {
1418
0
      name2 = cf_section_name2(subcs);
1419
0
      if (!name2) {
1420
0
        cf_log_err(subcs, "Invalid '%s { ... }' section, it must have a name", list[i].section->name1);
1421
0
        return -1;
1422
0
      }
1423
1424
      /*
1425
       *  Duplicate sections are forbidden.
1426
       */
1427
0
      bad = cf_section_find_next(server, subcs, list[i].section->name1, name2);
1428
0
      if (bad) goto forbidden;
1429
1430
0
      rcode = unlang_compile(vs, subcs, list[i].actions, rules, NULL);
1431
0
      if (rcode < 0) return -1;
1432
1433
      /*
1434
       *  Note that we don't store the
1435
       *  CONF_SECTION here, as it's a wildcard.
1436
       *
1437
       *  @todo - count number of subsections
1438
       *  and store them in an array?
1439
       */
1440
0
      found++;
1441
0
    }
1442
0
  }
1443
1444
  /*
1445
   *  Compile finally sections, these are special
1446
   *  sections and always execute before the request
1447
   *  exits from the virtual server.
1448
   */
1449
0
  if (unlikely(virtual_server_compile_finally_sections(vs, rules, &found) < 0)) {
1450
0
    cf_log_err(server, "Failed to compile finally sections");
1451
0
    return -1;
1452
0
  }
1453
1454
  /*
1455
   *  Didn't find any processing sections.  Note that we don't count "finally" sections here.  They
1456
   *  are only run after the packet has been processed through the normal sections.  A virtual
1457
   *  server with only a "finally" section doesn't make sense.
1458
   *
1459
   *  i.e. if people want to accept packets without responding, they need a "recv foo" section which
1460
   *  contains a "do_not_respond" policy.
1461
   */
1462
0
  if (!found) {
1463
0
    cf_log_err(server, "No processing sections are defined for this virtual server");
1464
0
    cf_log_err(server, "The server WILL NOT be able to process packets until the configuration is fixed");
1465
0
    return -1;
1466
0
  }
1467
1468
0
  if (!check_config && !DEBUG_ENABLED) return found;
1469
1470
0
  fail = virtual_server_warn_unused(server, list);
1471
1472
  /*
1473
   *  Be nice to people, and complaining about ALL unused processing sections.  That way they don't
1474
   *  have to run the server many, many, times to see all of the errors.
1475
   */
1476
0
  if (fail) return -1;
1477
1478
0
  return found;
1479
0
}
1480
1481
/** Register name1 / name2 as allowed processing sections
1482
 *
1483
 *  This function is called from the virtual server bootstrap routine,
1484
 *  which happens before module_bootstrap();
1485
 */
1486
int virtual_server_section_register(virtual_server_t *vs, virtual_server_compile_t const *entry)
1487
0
{
1488
0
  virtual_server_compile_t *old;
1489
1490
0
  fr_rb_find((void **)&old, vs->sections, entry);
1491
0
  if (old) return 0;
1492
1493
0
#ifndef NDEBUG
1494
  /*
1495
   *  Catch stupid programmers.
1496
   *
1497
   *  Processing sections can't allow "*" for module
1498
   *  methods, because otherwise you would be allowed to run
1499
   *  DHCP things in a RADIUS accounting section.  And that
1500
   *  would be bad.
1501
   */
1502
0
  if (entry->methods) {
1503
0
    int i;
1504
1505
0
    for (i = 0; entry->methods[i]; i++) {
1506
0
      if (entry->methods[i]->name1 == CF_IDENT_ANY) {
1507
0
        ERROR("Processing sections cannot allow \"*\"");
1508
0
        return -1;
1509
0
      }
1510
1511
0
      if (entry->methods[i]->name2 == CF_IDENT_ANY) {
1512
0
        ERROR("Processing sections cannot allow \"%s *\"",
1513
0
          entry->methods[i]->name1);
1514
0
        return -1;
1515
0
      }
1516
0
    }
1517
0
  }
1518
0
#endif
1519
1520
0
  if (fr_rb_insert(vs->sections, entry) != 0) {
1521
0
    fr_strerror_const("Failed inserting entry into internal tree");
1522
0
    return -1;
1523
0
  }
1524
1525
0
  return 0;
1526
0
}
1527
1528
/** Find the component for a section
1529
 *
1530
 */
1531
section_name_t const **virtual_server_section_methods(virtual_server_t const *vs, section_name_t const *section)
1532
0
{
1533
0
  virtual_server_compile_t *entry;
1534
1535
  /*
1536
   *  Look up the specific name first.  That way we can
1537
   *  define both "accounting on", and "accounting *".
1538
   */
1539
0
  if (section->name2 != CF_IDENT_ANY) {
1540
0
    fr_rb_find((void **)&entry, vs->sections,
1541
0
         &(virtual_server_compile_t) {
1542
0
        .section = section
1543
0
         });
1544
0
    if (entry) return entry->methods;
1545
0
  }
1546
1547
  /*
1548
   *  Then look up the wildcard, if we didn't find any matching name2.
1549
   */
1550
0
  fr_rb_find((void **)&entry, vs->sections,
1551
0
       &(virtual_server_compile_t) {
1552
0
      .section = SECTION_NAME(section->name1, CF_IDENT_ANY)
1553
0
       });
1554
0
  if (!entry) return NULL;
1555
1556
0
  return entry->methods;
1557
0
}
1558
1559
/** Define a values for Auth-Type attributes by the sections present in a virtual-server
1560
 *
1561
 * The.name2 value of any sections found will be converted into values of the specified da.
1562
 *
1563
 * @param[in] server_cs   The virtual server containing the sections.
1564
 * @param[in] subcs_name  of the subsection to search for.
1565
 * @param[in] da    to add enumeration values for.
1566
 * @return
1567
 *  - 0 all values added successfully.
1568
 *  - -1 an error occurred.
1569
 */
1570
int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const *subcs_name, fr_dict_attr_t const *da)
1571
0
{
1572
0
  int     rcode = 0;
1573
0
  CONF_SECTION    *subcs = NULL;
1574
1575
0
  fr_assert(strcmp(cf_section_name1(server_cs), "server") == 0);
1576
1577
0
  while ((subcs = cf_section_find_next(server_cs, subcs, subcs_name, CF_IDENT_ANY))) {
1578
0
    char const  *name2;
1579
0
    fr_dict_enum_value_t const  *dv;
1580
1581
0
    name2 = cf_section_name2(subcs);
1582
0
    if (!name2) {
1583
0
      cf_log_err(subcs, "Invalid '%s { ... }' section, it must have a name", subcs_name);
1584
0
      return -1;
1585
0
    }
1586
1587
    /*
1588
     *  If the value already exists, don't
1589
     *  create it again.
1590
     */
1591
0
    dv = fr_dict_enum_by_name(da, name2, -1);
1592
0
    if (dv) continue;
1593
1594
0
    cf_log_debug(subcs, "Creating %s = %s", da->name, name2);
1595
1596
    /*
1597
     *  Create a new unique value with a meaningless
1598
     *  number.  You can't look at it from outside of
1599
     *  this code, so it doesn't matter.  The only
1600
     *  requirement is that it's unique.
1601
     */
1602
0
    if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(da), name2) < 0) {
1603
0
      PERROR("Failed adding section value");
1604
0
      return -1;
1605
0
    }
1606
1607
0
    rcode = 1;
1608
0
  }
1609
1610
0
  return rcode;
1611
0
}
1612
1613
static int define_server_values(CONF_SECTION *cs, fr_dict_attr_t *parent)
1614
0
{
1615
0
  char const *ref;
1616
0
  fr_dict_attr_t const *da;
1617
0
  CONF_ITEM *ci = NULL;
1618
1619
0
  ref = cf_section_name2(cs);
1620
0
  if (!ref) {
1621
0
    cf_log_err(cs, "Expected 'values <name> { ... }'");
1622
0
    return -1;
1623
0
  }
1624
1625
0
  da = fr_dict_attr_by_name(NULL, parent, ref);
1626
0
  if (!da) {
1627
0
    cf_log_err(cs, "No such attribute \"%s\"", ref);
1628
0
    return -1;
1629
0
  }
1630
1631
0
  if (fr_type_is_structural(da->type)) {
1632
0
    cf_log_err(cs, "Cannot define value for structural attribute \"%s\"", ref);
1633
0
    return -1;
1634
0
  }
1635
1636
  /*
1637
   *  This both does not make any sense, and does not get
1638
   *  parsed correctly if the string contains backslashes.
1639
   */
1640
0
  if (da->type == FR_TYPE_STRING) {
1641
0
    cf_log_err(cs, "Cannot define value for 'string' attribute \"%s\"", ref);
1642
0
    return -1;
1643
0
  }
1644
1645
0
  while ((ci = cf_item_next(cs, ci))) {
1646
0
    fr_slen_t slen;
1647
0
    ssize_t len;
1648
0
    char const *attr, *value;
1649
0
    CONF_PAIR *cp;
1650
0
    fr_dict_enum_value_t const *dv;
1651
0
    fr_value_box_t box;
1652
1653
0
    if (cf_item_is_section(ci)) {
1654
0
      cf_log_err(ci, "Unexpected subsection");
1655
0
      return -1;
1656
0
    }
1657
1658
0
    if (!cf_item_is_pair(ci)) continue;
1659
1660
0
    cp = cf_item_to_pair(ci);
1661
0
    fr_assert(cp != NULL);
1662
1663
    /*
1664
     *  =* is a hack by the cf parser to say "no operator"
1665
     */
1666
0
    if ((cf_pair_operator(cp) != T_OP_EQ) ||
1667
0
        (cf_pair_attr_quote(cp) != T_BARE_WORD)) {
1668
0
      cf_log_err(ci, "Definition is not in 'name = value' format");
1669
0
      return -1;
1670
0
    }
1671
1672
0
    attr = cf_pair_attr(cp);
1673
0
    value = cf_pair_value(cp);
1674
1675
0
    dv = fr_dict_enum_by_name(da, attr, talloc_strlen(attr));
1676
0
    if (dv) {
1677
0
      cf_log_err(cp, "Duplicate value name");
1678
0
      return -1;
1679
0
    }
1680
1681
0
    fr_value_box_init_null(&box);
1682
1683
0
    len = talloc_strlen(value);
1684
1685
    /*
1686
     *  @todo - unescape for double quoted strings.  Whoops.
1687
     */
1688
0
    slen = fr_value_box_from_str(NULL, &box, da->type, da, value, len, NULL);
1689
0
    if (slen < 0) {
1690
0
      cf_log_err(cp, "Failed parsing value - %s", fr_strerror());
1691
0
      return -1;
1692
0
    }
1693
1694
0
    if (slen != len) {
1695
0
      cf_log_err(cp, "Unexpected text after value");
1696
0
      fr_value_box_clear(&box);
1697
0
      return -1;
1698
0
    }
1699
1700
0
    if (fr_dict_enum_add_name(UNCONST(fr_dict_attr_t *, da), attr, &box, false, false) < 0) {
1701
0
      cf_log_err(cp, "Failed adding value - %s", fr_strerror());
1702
0
      fr_value_box_clear(&box);
1703
0
      return -1;
1704
0
    }
1705
1706
0
    fr_value_box_clear(&box);
1707
0
  }
1708
1709
0
  return 0;
1710
0
}
1711
1712
1713
static int define_server_attrs(CONF_SECTION *cs, fr_dict_t *dict, fr_dict_attr_t *parent, fr_dict_attr_t const *root)
1714
0
{
1715
0
  CONF_ITEM *ci = NULL;
1716
1717
0
  fr_dict_attr_flags_t flags = {
1718
0
    .internal = true,
1719
0
    .name_only = true,
1720
0
    .local = true,
1721
0
  };
1722
1723
0
  fr_assert(dict != NULL);
1724
0
  fr_assert(parent != NULL);
1725
1726
0
  while ((ci = cf_item_next(cs, ci))) {
1727
0
    fr_type_t type;
1728
0
    char const *attr, *value;
1729
0
    CONF_PAIR *cp;
1730
0
    CONF_SECTION *subcs = NULL;
1731
1732
0
    if (cf_item_is_section(ci)) {
1733
0
      subcs = cf_item_to_section(ci);
1734
0
      fr_assert(subcs != NULL);
1735
1736
0
      attr = cf_section_name1(subcs);
1737
1738
0
      if (strcmp(attr, "values") == 0) {
1739
0
        if (define_server_values(subcs, parent) < 0) return -1;
1740
0
        continue;
1741
0
      }
1742
1743
0
      if (strcmp(attr, "tlv") != 0) goto invalid_type;
1744
1745
0
      value = cf_section_name2(subcs);
1746
0
      if (!value) {
1747
0
        cf_log_err(ci, "Definition is not in 'tlv name { ... }' format");
1748
0
        return -1;
1749
0
      }
1750
1751
0
      type = FR_TYPE_TLV;
1752
0
      goto check_for_dup;
1753
0
    }
1754
1755
0
    if (!cf_item_is_pair(ci)) continue;
1756
1757
0
    cp = cf_item_to_pair(ci);
1758
0
    fr_assert(cp != NULL);
1759
1760
    /*
1761
     *  =* is a hack by the cf parser to say "no operator"
1762
     */
1763
0
    if ((cf_pair_operator(cp) != T_OP_CMP_TRUE) ||
1764
0
        (cf_pair_attr_quote(cp) != T_BARE_WORD) ||
1765
0
        (cf_pair_value_quote(cp) != T_BARE_WORD)) {
1766
0
      cf_log_err(ci, "Definition is not in 'type name' format");
1767
0
      return -1;
1768
0
    }
1769
1770
0
    attr = cf_pair_attr(cp);
1771
0
    value = cf_pair_value(cp);
1772
1773
0
    type = fr_table_value_by_str(fr_type_table, attr, FR_TYPE_NULL);
1774
0
    if (type == FR_TYPE_NULL) {
1775
0
    invalid_type:
1776
0
      cf_log_err(ci, "Invalid data type '%s'", attr);
1777
0
      return -1;
1778
0
    }
1779
1780
    /*
1781
     *  Leaf and group are OK.  TLV, Vendor, Struct, VSA, etc. are not as variable definitions.
1782
     */
1783
0
    if (!(fr_type_is_leaf(type) || (type == FR_TYPE_GROUP))) goto invalid_type;
1784
1785
    /*
1786
     *  No duplicates are allowed.
1787
     */
1788
0
  check_for_dup:
1789
0
    if (root && (fr_dict_attr_by_name(NULL, root, value) != NULL)) {
1790
0
      cf_log_err(ci, "Local variable '%s' duplicates a dictionary attribute.", value);
1791
0
      return -1;
1792
0
    }
1793
1794
0
    if (fr_dict_attr_by_name(NULL, parent, value) != NULL) {
1795
0
      cf_log_err(ci, "Local variable '%s' duplicates a previous local attribute.", value);
1796
0
      return -1;
1797
0
    }
1798
1799
0
    if (fr_dict_attr_add_name_only(dict, parent, value, type, &flags) < 0) {
1800
0
      cf_log_err(ci, "Failed adding local variable '%s' - %s", value, fr_strerror());
1801
0
      return -1;
1802
0
    }
1803
1804
0
    if (type == FR_TYPE_TLV) {
1805
0
      fr_dict_attr_t const *da;
1806
1807
0
      if (!subcs) return -1; /* shouldn't happen, but shut up compiler */
1808
1809
0
      da = fr_dict_attr_by_name(NULL, parent, value);
1810
0
      fr_assert(da != NULL);
1811
1812
0
      if (define_server_attrs(subcs, dict, UNCONST(fr_dict_attr_t *, da), NULL) < 0) return -1;
1813
0
    }
1814
0
  }
1815
1816
0
  return 0;
1817
0
}
1818
1819
static fr_dict_t const *virtual_server_local_dict(CONF_SECTION *server_cs, fr_dict_t const *dict_def)
1820
0
{
1821
0
  fr_dict_t *dict;
1822
0
  CONF_SECTION *cs;
1823
1824
0
  cs = cf_section_find(server_cs, "dictionary", NULL);
1825
0
  if (!cs) return dict_def;
1826
1827
0
  dict = fr_dict_protocol_alloc(dict_def);
1828
0
  if (!dict) {
1829
0
    cf_log_err(cs, "Failed allocating local dictionary");
1830
0
    return NULL;
1831
0
  }
1832
1833
0
  if (define_server_attrs(cs, dict, UNCONST(fr_dict_attr_t *, fr_dict_root(dict)), fr_dict_root(dict_def)) < 0){
1834
0
    talloc_free(dict);
1835
0
    return NULL;
1836
0
  }
1837
1838
  /*
1839
   *  Replace the original dictionary with the new one.
1840
   */
1841
0
  cf_data_remove(server_cs, fr_dict_t, "dict");
1842
0
  cf_data_add(server_cs, dict, "dict", false);
1843
0
  cf_item_mark_parsed(cs);
1844
1845
0
  return dict;
1846
0
}
1847
1848
1849
/** Open all the listen sockets
1850
 *
1851
 * @param[in] sc  Scheduler to add I/O paths to.
1852
 * @return
1853
 *  - 0 on success.
1854
 *  - -1 on failure.
1855
 */
1856
int virtual_servers_open(fr_schedule_t *sc)
1857
0
{
1858
0
  size_t i, server_cnt = virtual_servers ? talloc_array_length(virtual_servers) : 0;
1859
0
  int opened = 0;
1860
1861
0
  fr_assert(virtual_servers);
1862
1863
0
  DEBUG2("#### Opening listener interfaces ####");
1864
0
  fr_strerror_clear();
1865
1866
0
  for (i = 0; i < server_cnt; i++) {
1867
0
    virtual_server_listen_t **listeners;
1868
0
    size_t      j, listener_cnt;
1869
1870
0
    listeners = virtual_servers[i]->listeners;
1871
0
    if (!listeners) continue; /* servers can have no listeners */
1872
1873
0
    listener_cnt = talloc_array_length(listeners);
1874
1875
0
    for (j = 0; j < listener_cnt; j++) {
1876
0
      int ret;
1877
0
      virtual_server_listen_t *listener = listeners[j];
1878
1879
0
      fr_assert(listener != NULL);
1880
0
      fr_assert(listener->proto_mi != NULL);
1881
0
      fr_assert(listener->proto_module != NULL);
1882
1883
0
      fr_assert(listener->proto_module->open != NULL);
1884
1885
      /*
1886
       *  The socket is opened with app_instance,
1887
       *  but all subsequent calls (network.c, etc.) use app_io_instance.
1888
       *
1889
       *  The reason is that we call (for example) proto_radius to
1890
       *  open the socket, and proto_radius is responsible for setting up
1891
       *  proto_radius_udp, and then calling proto_radius_udp->open.
1892
       *
1893
       *  Even then, proto_radius usually calls fr_master_io_listen() in order
1894
       *  to create the fr_listen_instance_t structure.
1895
       */
1896
1897
      /*
1898
       *  Sometimes the open function needs to modify instance
1899
       *  data, so we need to temporarily remove the protection.
1900
       */
1901
0
      module_instance_data_unprotect(listener->proto_mi);
1902
0
      ret = listener->proto_module->open(listener->proto_mi->data, sc,
1903
0
                 listener->proto_mi->conf);
1904
0
      module_instance_data_protect(listener->proto_mi);
1905
0
      if (unlikely(ret < 0)) {
1906
0
        return -1;
1907
0
      }
1908
1909
0
      opened++;
1910
1911
      /*
1912
       *  Socket information is printed out by
1913
       *  the socket handlers.  e.g. proto_radius_udp
1914
       */
1915
0
      DEBUG3("Opened listener for %s", listener->proto_module->common.name);
1916
0
    }
1917
0
  }
1918
1919
0
  if (!opened) {
1920
0
    ERROR("There are no 'listen' sections defined.");
1921
0
    ERROR("Refusing to start, as the server will never process any packets.");
1922
0
    return -1;
1923
0
  }
1924
1925
0
  return 0;
1926
0
}
1927
1928
/** Free thread-specific data for all process modules and listeners
1929
 *
1930
 */
1931
void virtual_servers_thread_detach(void)
1932
0
{
1933
0
  modules_thread_detach(proto_modules);
1934
0
  modules_thread_detach(process_modules);
1935
0
}
1936
1937
/** Perform thread instantiation for all process modules and listeners
1938
 *
1939
 */
1940
int virtual_servers_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
1941
0
{
1942
0
  if (modules_thread_instantiate(ctx, process_modules, el) < 0) return -1;
1943
0
  if (modules_thread_instantiate(ctx, proto_modules, el) < 0) {
1944
0
    modules_thread_detach(process_modules);
1945
0
    return -1;
1946
0
  }
1947
0
  return 0;
1948
0
}
1949
1950
/** Instantiate all the virtual servers
1951
 *
1952
 * @return
1953
 *  - 0 on success.
1954
 *  - -1 on failure.
1955
 */
1956
int virtual_servers_instantiate(void)
1957
0
{
1958
0
  size_t  i, server_cnt;
1959
0
  CONF_SECTION *cs;
1960
0
  fr_rb_iter_inorder_t iter;
1961
1962
  /*
1963
   *  User didn't specify any "server" sections
1964
   */
1965
0
  if (unlikely(!virtual_servers)) {
1966
0
    ERROR("No virtual servers configured");
1967
0
    return -1;
1968
0
  }
1969
1970
0
  server_cnt = talloc_array_length(virtual_servers);
1971
1972
0
  DEBUG2("#### Instantiating listeners ####");
1973
1974
0
  if (fr_command_register_hook(NULL, NULL, virtual_server_root, cmd_table) < 0) {
1975
0
    PERROR("Failed registering radmin commands for virtual servers");
1976
0
    return -1;
1977
0
  }
1978
1979
0
  for (i = 0; i < server_cnt; i++) {
1980
0
    CONF_SECTION      *server_cs = virtual_servers[i]->server_cs;
1981
0
    fr_dict_t const     *dict;
1982
0
    virtual_server_t    *vs = virtual_servers[i];
1983
0
    fr_process_module_t const *process = (fr_process_module_t const *)
1984
0
                  vs->process_mi->module->exported;
1985
1986
    /*
1987
     *  Set up logging before doing anything else.
1988
     */
1989
0
    if (vs->log_name) {
1990
0
      vs->log = log_dst_by_name(vs->log_name);
1991
0
      if (!vs->log) {
1992
0
        CONF_PAIR *cp = cf_pair_find(server_cs, "log");
1993
1994
0
        if (cp) {
1995
0
          cf_log_err(cp, "Unknown log destination '%s'", vs->log_name);
1996
0
        } else {
1997
0
          cf_log_err(server_cs, "Unknown log destination '%s'", vs->log_name);
1998
0
        }
1999
2000
0
        return -1;
2001
0
      }
2002
0
    }
2003
2004
0
    dict = virtual_server_local_dict(server_cs, *(process)->dict);
2005
0
    if (!dict) return -1;
2006
2007
0
    DEBUG("Compiling policies in server %s { ... }", cf_section_name2(server_cs));
2008
2009
0
    fr_assert(virtual_servers[i]->process_mi);
2010
2011
    /*
2012
     *  Compile the processing sections indicated by
2013
     *      the process module.  This must be done before
2014
     *  module_instantiate is called, as the instance
2015
     *  data is protected after this call.
2016
     */
2017
0
    if (process->compile_list) {
2018
0
      tmpl_rules_t    parse_rules = {
2019
0
        .attr = {
2020
0
          .dict_def = dict,
2021
0
          .list_def = request_attr_request,
2022
0
        },
2023
2024
0
        .literals_safe_for = FR_VALUE_BOX_SAFE_FOR_ANY,
2025
0
      };
2026
2027
0
      fr_assert(parse_rules.attr.dict_def != NULL);
2028
2029
0
      if (virtual_server_compile_sections(virtual_servers[i], &parse_rules) < 0) {
2030
0
        return -1;
2031
0
      }
2032
0
    }
2033
2034
0
    (void) virtual_server_warn_unused(server_cs, process->compile_list);
2035
0
  }
2036
2037
  /*
2038
   *  Iterate over virtual modules to see if we can compile them.
2039
   */
2040
0
  for (cs = module_rlm_virtual_iter_init(&iter);
2041
0
       cs != NULL;
2042
0
       cs = module_rlm_virtual_iter_next(&iter)) {
2043
0
    fr_dict_t const *dict;
2044
2045
0
    dict = virtual_server_dict_by_cs(cs); /* cheating! */
2046
0
    if (!dict) continue;
2047
2048
0
    if (unlang_compile_virtual_module(cs, dict) < 0) return -1;
2049
0
  }
2050
2051
0
  if (modules_instantiate(process_modules) < 0) {
2052
0
    PERROR("Failed instantiating process modules");
2053
0
    return -1;
2054
0
  }
2055
0
  if (modules_instantiate(proto_modules) < 0) {
2056
0
    PERROR("Failed instantiating protocol modules");
2057
0
    return -1;
2058
0
  }
2059
2060
0
  return 0;
2061
0
}
2062
2063
/** Load protocol modules and call their bootstrap methods
2064
 *
2065
 * @param[in] config  section containing the virtual servers to bootstrap.
2066
 * @return
2067
 *  - 0 on success.
2068
 *  - -1 on failure.
2069
 */
2070
int virtual_servers_bootstrap(CONF_SECTION *config)
2071
0
{
2072
0
  virtual_server_root = config;
2073
2074
  /*
2075
   *  Ensure any libraries the modules depend on are instantiated
2076
   */
2077
0
  if (global_lib_instantiate() < 0) return -1;
2078
2079
0
  if (modules_bootstrap(process_modules) < 0) {
2080
0
    PERROR("Failed bootstrapping process modules");
2081
0
    return -1;
2082
0
  }
2083
0
  if (modules_bootstrap(proto_modules) < 0) {
2084
0
    PERROR("Failed bootstrapping protocol modules");
2085
0
    return -1;
2086
0
  }
2087
2088
0
  return 0;
2089
0
}
2090
2091
int virtual_servers_free(void)
2092
0
{
2093
0
  if (talloc_free(listen_addr_root) < 0) return -1;
2094
0
  listen_addr_root = NULL;
2095
0
  if (talloc_free(process_modules) < 0) return -1;
2096
0
  process_modules = NULL;
2097
0
  if (talloc_free(proto_modules) < 0) return -1;
2098
0
  proto_modules = NULL;
2099
0
  if (fr_dict_autofree(virtual_server_dict_autoload) < 0) return -1;
2100
2101
0
  return 0;
2102
0
}
2103
2104
static int _virtual_servers_atexit(UNUSED void *uctx)
2105
0
{
2106
0
  return virtual_servers_free();
2107
0
}
2108
2109
/** Performs global initialisation for the virtual server code
2110
 *
2111
 * This has to be done separately and explicitly, because the above code makes
2112
 * use of "onread" callbacks.
2113
 *
2114
 * Will automatically free module lists on exit, but all modules should have
2115
 * been removed from this list by the point that happens.
2116
 */
2117
int virtual_servers_init(void)
2118
{
2119
  if (fr_dict_autoload(virtual_server_dict_autoload) < 0) {
2120
    PERROR("%s", __FUNCTION__);
2121
    return -1;
2122
  }
2123
  if (fr_dict_attr_autoload(virtual_server_dict_attr_autoload) < 0) {
2124
    PERROR("%s", __FUNCTION__);
2125
    fr_dict_autofree(virtual_server_dict_autoload);
2126
    return -1;
2127
  }
2128
2129
  MEM(process_modules = module_list_alloc(NULL, &module_list_type_global, "process", true));
2130
2131
  /*
2132
   *  FIXME - We should be able to turn on write protection,
2133
   *  but there are too many proto modules that hang things
2134
   *  off of their instance data.
2135
   */
2136
  MEM(proto_modules = module_list_alloc(NULL, &module_list_type_global, "protocol", false));
2137
  MEM(listen_addr_root = fr_rb_inline_alloc(NULL, fr_listen_instance_t, virtual_server_node, listen_addr_cmp,
2138
              NULL));
2139
2140
  /*
2141
   *  Create a list to hold all the proto_* modules
2142
   *  that get loaded during startup.
2143
   */
2144
  fr_atexit_global(_virtual_servers_atexit, NULL);
2145
2146
  return 0;
2147
}