The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_radius.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 81ed6af31508a99cfc37180f7fee41bf863d9260 $
19  * @file rlm_radius.c
20  * @brief A RADIUS client library.
21  *
22  * @copyright 2016 The FreeRADIUS server project
23  * @copyright 2016 Network RADIUS SAS
24  */
25 RCSID("$Id: 81ed6af31508a99cfc37180f7fee41bf863d9260 $")
26 
27 #include <freeradius-devel/io/application.h>
28 #include <freeradius-devel/server/modpriv.h>
29 #include <freeradius-devel/util/debug.h>
30 #include <freeradius-devel/util/dlist.h>
31 
32 #include "rlm_radius.h"
33 
34 static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
35 static int status_check_type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
36 static int status_check_update_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
37 
39  { FR_CONF_OFFSET_TYPE_FLAGS("type", FR_TYPE_VOID, 0, rlm_radius_t, status_check),
40  .func = status_check_type_parse },
41 
43 };
44 
47  .name2 = CF_IDENT_ANY,
48  .func = status_check_update_parse },
49  { FR_CONF_OFFSET("num_answers_to_alive", rlm_radius_t, num_answers_to_alive), .dflt = STRINGIFY(3) },
50 
52 };
53 
54 /*
55  * Retransmission intervals for the packets we support.
56  */
58  { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].irt), .dflt = STRINGIFY(2) },
59  { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrt), .dflt = STRINGIFY(16) },
60  { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrc), .dflt = STRINGIFY(5) },
61  { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrd), .dflt = STRINGIFY(30) },
63 };
64 
66  { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].irt), .dflt = STRINGIFY(2) },
67  { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrt), .dflt = STRINGIFY(5) },
68  { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrc), .dflt = STRINGIFY(1) },
69  { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrd), .dflt = STRINGIFY(30) },
71 };
72 
74  { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].irt), .dflt = STRINGIFY(2) },
75  { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].mrt), .dflt = STRINGIFY(5) },
76  { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].mrc), .dflt = STRINGIFY(5) },
77  { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].mrd), .dflt = STRINGIFY(30) },
79 };
80 
82  { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].irt), .dflt = STRINGIFY(2) },
83  { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].mrt), .dflt = STRINGIFY(16) },
84  { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].mrc), .dflt = STRINGIFY(5) },
85  { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].mrd), .dflt = STRINGIFY(30) },
87 };
88 
90  { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].irt), .dflt = STRINGIFY(2) },
91  { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrt), .dflt = STRINGIFY(16) },
92  { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrc), .dflt = STRINGIFY(5) },
93  { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd), .dflt = STRINGIFY(30) },
95 };
96 
97 
98 /*
99  * A mapping of configuration file names to internal variables.
100  */
101 static conf_parser_t const module_config[] = {
102  { FR_CONF_OFFSET_TYPE_FLAGS("transport", FR_TYPE_VOID, 0, rlm_radius_t, io_submodule),
103  .func = module_rlm_submodule_parse },
104 
106  .func = type_parse },
107 
108  { FR_CONF_OFFSET("replicate", rlm_radius_t, replicate) },
109 
110  { FR_CONF_OFFSET("synchronous", rlm_radius_t, synchronous) },
111 
112  { FR_CONF_OFFSET("originate", rlm_radius_t, originate) },
113 
114  { FR_CONF_POINTER("status_check", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) status_check_config },
115 
116  { FR_CONF_OFFSET("max_attributes", rlm_radius_t, max_attributes), .dflt = STRINGIFY(RADIUS_MAX_ATTRIBUTES) },
117 
118  { FR_CONF_OFFSET("require_message_authenticator", rlm_radius_t, require_message_authenticator),
119  .func = cf_table_parse_int,
121  .dflt = "no" },
122 
123  { FR_CONF_OFFSET("response_window", rlm_radius_t, response_window), .dflt = STRINGIFY(20) },
124 
125  { FR_CONF_OFFSET("zombie_period", rlm_radius_t, zombie_period), .dflt = STRINGIFY(40) },
126 
127  { FR_CONF_OFFSET("revive_interval", rlm_radius_t, revive_interval) },
128 
129  { FR_CONF_OFFSET_SUBSECTION("pool", 0, rlm_radius_t, trunk_conf, trunk_config ) },
130 
132 };
133 
135  [FR_RADIUS_CODE_ACCESS_REQUEST] = { FR_CONF_POINTER("Access-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) auth_config },
136 
137  [FR_RADIUS_CODE_ACCOUNTING_REQUEST] = { FR_CONF_POINTER("Accounting-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) acct_config },
138  [FR_RADIUS_CODE_STATUS_SERVER] = { FR_CONF_POINTER("Status-Server", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) status_config },
139  [FR_RADIUS_CODE_COA_REQUEST] = { FR_CONF_POINTER("CoA-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) coa_config },
140  [FR_RADIUS_CODE_DISCONNECT_REQUEST] = { FR_CONF_POINTER("Disconnect-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) disconnect_config },
141 };
142 
143 static fr_dict_t const *dict_radius;
144 
147  { .out = &dict_radius, .proto = "radius" },
148  { NULL }
149 };
150 
155 
158  { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
159  { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
160  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
161  { .out = &attr_proxy_state, .name = "Proxy-State", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
162  { NULL }
163 };
164 
165 /** Set which types of packets we can parse
166  *
167  * @param[in] ctx to allocate data in (instance of rlm_radius).
168  * @param[out] out Where to write the parsed data.
169  * @param[in] parent Base structure address.
170  * @param[in] ci #CONF_PAIR specifying the name of the type module.
171  * @param[in] rule unused.
172  * @return
173  * - 0 on success.
174  * - -1 on failure.
175  */
176 static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
177  CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
178 {
179  char const *type_str = cf_pair_value(cf_item_to_pair(ci));
181  fr_dict_enum_value_t const *type_enum;
182  uint32_t code;
183 
184  /*
185  * Must be the RADIUS module
186  */
187  fr_assert(cs && (strcmp(cf_section_name1(cs), "radius") == 0));
188 
189  /*
190  * Allow the process module to be specified by
191  * packet type.
192  */
193  type_enum = fr_dict_enum_by_name(attr_packet_type, type_str, -1);
194  if (!type_enum) {
195  invalid_code:
196  cf_log_err(ci, "Unknown or invalid RADIUS packet type '%s'", type_str);
197  return -1;
198  }
199 
200  code = type_enum->value->vb_uint32;
201 
202  /*
203  * Status-Server packets cannot be proxied.
204  */
205  if (code == FR_RADIUS_CODE_STATUS_SERVER) {
206  cf_log_err(ci, "Invalid setting of 'type = Status-Server'. Status-Server packets cannot be proxied.");
207  return -1;
208  }
209 
210  if (!code ||
211  (code >= FR_RADIUS_CODE_MAX) ||
212  (!type_interval_config[code].name1)) goto invalid_code;
213 
214  /*
215  * If we're doing async proxying, push the timers for the
216  * various packet types.
217  */
219 
220  memcpy(out, &code, sizeof(code));
221 
222  return 0;
223 }
224 
225 /** Allow for Status-Server ping checks
226  *
227  * @param[in] ctx to allocate data in (instance of proto_radius).
228  * @param[out] out Where to write our parsed data.
229  * @param[in] parent Base structure address.
230  * @param[in] ci #CONF_PAIR specifying the name of the type module.
231  * @param[in] rule unused.
232  * @return
233  * - 0 on success.
234  * - -1 on failure.
235  */
236 static int status_check_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
237  CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
238 {
239  char const *type_str = cf_pair_value(cf_item_to_pair(ci));
241  fr_dict_enum_value_t const *type_enum;
242  uint32_t code;
243 
244  /*
245  * Allow the process module to be specified by
246  * packet type.
247  */
248  type_enum = fr_dict_enum_by_name(attr_packet_type, type_str, -1);
249  if (!type_enum) {
250  invalid_code:
251  cf_log_err(ci, "Unknown or invalid RADIUS packet type '%s'", type_str);
252  return -1;
253  }
254 
255  code = type_enum->value->vb_uint32;
256 
257  /*
258  * Cheat, and reuse the "type" array for allowed packet
259  * types.
260  */
261  if (!code ||
262  (code >= FR_RADIUS_CODE_MAX) ||
263  (!type_interval_config[code].name1)) goto invalid_code;
264 
265  /*
266  * Add irt / mrt / mrd / mrc parsing, in the parent
267  * configuration section.
268  */
270 
271  memcpy(out, &code, sizeof(code));
272 
273  /*
274  * Nothing more to do here, so we stop.
275  */
276  if (code == FR_RADIUS_CODE_STATUS_SERVER) return 0;
277 
279 
280  return 0;
281 }
282 
283 /** Allow the admin to set packet contents for Status-Server ping checks
284  *
285  * @param[in] ctx to allocate data in (instance of proto_radius).
286  * @param[out] out Where to write our parsed data
287  * @param[in] parent Base structure address.
288  * @param[in] ci #CONF_SECTION specifying the things to update
289  * @param[in] rule unused.
290  * @return
291  * - 0 on success.
292  * - -1 on failure.
293  */
294 static int status_check_update_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
295  CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
296 {
297  int rcode;
298  CONF_SECTION *cs;
299  char const *name2;
300  map_list_t *head = (map_list_t *)out;
301 
303  map_list_init(head);
304 
305  cs = cf_item_to_section(ci);
306  name2 = cf_section_name2(cs);
307  if (!name2 || (strcmp(name2, "request") != 0)) {
308  cf_log_err(cs, "You must specify 'request' as the destination list");
309  return -1;
310  }
311 
312  /*
313  * Compile the "update" section.
314  */
315  {
316  tmpl_rules_t parse_rules = {
317  .attr = {
319  }
320  };
321 
322  rcode = map_afrom_cs(ctx, head, cs, &parse_rules, &parse_rules, unlang_fixup_update, NULL, 128);
323  if (rcode < 0) return -1; /* message already printed */
324  if (map_list_empty(head)) {
325  cf_log_err(cs, "'update' sections cannot be empty");
326  return -1;
327  }
328  }
329 
330  /*
331  * Rely on "bootstrap" to do sanity checks between 'type
332  * = Access-Request', and 'update' containing passwords.
333  */
334  return 0;
335 }
336 
337 
338 static void mod_radius_signal(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
339 {
341  rlm_radius_io_t const *io = (rlm_radius_io_t const *)inst->io_submodule->exported; /* Public symbol exported by the module */
342 
343  /*
344  * We received a duplicate packet, but we're not doing
345  * synchronous proxying. Ignore the dup, and rely on the
346  * IO submodule to time it's own retransmissions.
347  */
348  if ((action == FR_SIGNAL_DUP) && !inst->synchronous) return;
349 
350  if (!io->signal) return;
351 
352  io->signal(MODULE_CTX(inst->io_submodule,
353  module_thread(inst->io_submodule)->data, mctx->env_data,
354  mctx->rctx), request, action);
355 }
356 
357 /** Do any RADIUS-layer fixups for proxying.
358  *
359  */
360 static void radius_fixups(rlm_radius_t const *inst, request_t *request)
361 {
362  fr_pair_t *vp;
363 
364  /*
365  * Check for proxy loops.
366  */
367  if (!inst->originate && RDEBUG_ENABLED) {
368  fr_dcursor_t cursor;
369 
370  for (vp = fr_pair_dcursor_by_da_init(&cursor, &request->request_pairs, attr_proxy_state);
371  vp;
372  vp = fr_dcursor_next(&cursor)) {
373  if (vp->vp_length != 4) continue;
374 
375  if (memcmp(&inst->proxy_state, vp->vp_octets, 4) == 0) {
376  RWARN("Possible proxy loop - please check server configuration.");
377  break;
378  }
379  }
380  }
381 
382  if (request->packet->code != FR_RADIUS_CODE_ACCESS_REQUEST) return;
383 
384  if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password) &&
385  !fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_challenge)) {
387  fr_pair_value_memdup(vp, request->packet->vector, sizeof(request->packet->vector), true);
388  }
389 }
390 
391 
392 /** Send packets outbound.
393  *
394  */
395 static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
396 {
398  rlm_rcode_t rcode;
399  unlang_action_t ua;
400  fr_client_t *client;
401 
402  void *rctx = NULL;
403 
404  if (!request->packet->code) {
405  REDEBUG("You MUST specify a packet code");
407  }
408 
409  /*
410  * Reserve Status-Server for ourselves, for link-specific
411  * signaling.
412  */
413  if (request->packet->code == FR_RADIUS_CODE_STATUS_SERVER) {
414  REDEBUG("Cannot proxy Status-Server packets");
416  }
417 
418  if ((request->packet->code >= FR_RADIUS_CODE_MAX) ||
419  !fr_time_delta_ispos(inst->retry[request->packet->code].irt)) { /* can't be zero */
420  REDEBUG("Invalid packet code %d", request->packet->code);
422  }
423 
424  if (!inst->allowed[request->packet->code]) {
425  REDEBUG("Packet code %s is disallowed by the configuration",
426  fr_radius_packet_name[request->packet->code]);
428  }
429 
430  client = client_from_request(request);
431  if (client && client->dynamic && !client->active) {
432  REDEBUG("Cannot proxy packets which define dynamic clients");
434  }
435 
436  /*
437  * Do any necessary RADIUS level fixups
438  * - check Proxy-State
439  * - do CHAP-Challenge fixups
440  */
441  radius_fixups(inst, request);
442 
443  /*
444  * Push the request and it's data to the IO submodule.
445  *
446  * This may return YIELD, for "please yield", or it may
447  * return another code which indicates what happened to
448  * the request...
449  */
450  ua = inst->io->enqueue(&rcode, &rctx, inst->io_submodule->data,
451  module_thread(inst->io_submodule)->data, request);
452  if (ua != UNLANG_ACTION_YIELD) {
453  fr_assert(rctx == NULL);
454  RETURN_MODULE_RCODE(rcode);
455  }
456 
457  return unlang_module_yield(request, inst->io->resume, mod_radius_signal, 0, rctx);
458 }
459 
460 static int mod_instantiate(module_inst_ctx_t const *mctx)
461 {
462  size_t i, num_types;
463  rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
464  CONF_SECTION *conf = mctx->mi->conf;
465 
466  inst->io = (rlm_radius_io_t const *)inst->io_submodule->exported; /* Public symbol exported by the module */
467  inst->name = mctx->mi->name;
468  inst->received_message_authenticator = talloc_zero(NULL, bool); /* Allocated outside of inst to default protection */
469 
470  /*
471  * These limits are specific to RADIUS, and cannot be over-ridden
472  */
473  FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, >=, 2);
474  FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, <=, 255);
475  FR_INTEGER_BOUND_CHECK("trunk.per_connection_target", inst->trunk_conf.target_req_per_conn, <=, inst->trunk_conf.max_req_per_conn / 2);
476 
477  FR_TIME_DELTA_BOUND_CHECK("response_window", inst->zombie_period, >=, fr_time_delta_from_sec(1));
478  FR_TIME_DELTA_BOUND_CHECK("response_window", inst->zombie_period, <=, fr_time_delta_from_sec(120));
479 
480  FR_TIME_DELTA_BOUND_CHECK("zombie_period", inst->zombie_period, >=, fr_time_delta_from_sec(1));
481  FR_TIME_DELTA_BOUND_CHECK("zombie_period", inst->zombie_period, <=, fr_time_delta_from_sec(120));
482 
483  if (!inst->status_check) {
484  FR_TIME_DELTA_BOUND_CHECK("revive_interval", inst->revive_interval, >=, fr_time_delta_from_sec(10));
485  FR_TIME_DELTA_BOUND_CHECK("revive_interval", inst->revive_interval, <=, fr_time_delta_from_sec(3600));
486  }
487 
488  num_types = talloc_array_length(inst->types);
489  fr_assert(num_types > 0);
490 
491  /*
492  * Allow for O(1) lookup later...
493  */
494  for (i = 0; i < num_types; i++) {
495  uint32_t code;
496 
497  code = inst->types[i];
498  fr_assert(code > 0);
500 
501  inst->allowed[code] = true;
502  }
503 
504  fr_assert(inst->status_check < FR_RADIUS_CODE_MAX);
505 
506  /*
507  * If we're replicating, we don't care if the other end
508  * is alive.
509  */
510  if (inst->replicate && inst->status_check) {
511  cf_log_warn(conf, "Ignoring 'status_check = %s' due to 'replicate = true'",
512  fr_radius_packet_name[inst->status_check]);
513  inst->status_check = 0;
514  }
515 
516 
517  /*
518  * If we have status checks, then do some sanity checks.
519  * Status-Server is always allowed. Otherwise, the
520  * status checks have to match one of the allowed
521  * packets.
522  */
523  if (inst->status_check) {
524  if (inst->status_check == FR_RADIUS_CODE_STATUS_SERVER) {
525  inst->allowed[inst->status_check] = true;
526 
527  } else if (!inst->allowed[inst->status_check]) {
528  cf_log_err(conf, "Using 'status_check = %s' requires also 'type = %s'",
529  fr_radius_packet_name[inst->status_check], fr_radius_packet_name[inst->status_check]);
530  return -1;
531  }
532 
533  /*
534  * @todo - check the contents of the "update"
535  * section, to be sure that (e.g.) Access-Request
536  * contains User-Name, etc.
537  */
538  }
539 
540  /*
541  * Don't sanity check the async timers if we're doing
542  * synchronous proxying.
543  */
544  if (inst->synchronous) goto setup_io_submodule;
545 
546  /*
547  * Set limits on retransmission timers
548  */
549  if (inst->allowed[FR_RADIUS_CODE_ACCESS_REQUEST]) {
550  FR_TIME_DELTA_BOUND_CHECK("Access-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].irt, >=, fr_time_delta_from_sec(1));
551  FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
552  FR_INTEGER_BOUND_CHECK("Access-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrc, >=, 1);
553  FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrd, >=, fr_time_delta_from_sec(5));
554 
555  FR_TIME_DELTA_BOUND_CHECK("Access-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].irt, <=, fr_time_delta_from_sec(3));
556  FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrt, <=, fr_time_delta_from_sec(30));
557  FR_INTEGER_BOUND_CHECK("Access-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrc, <=, 10);
558  FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
559  }
560 
561  /*
562  * Note that RFC 5080 allows for Accounting-Request to
563  * have mrt=mrc=mrd = 0, which means "retransmit
564  * forever". We allow that, with the restriction that
565  * the server core will automatically free the request at
566  * max_request_time.
567  */
568  if (inst->allowed[FR_RADIUS_CODE_ACCOUNTING_REQUEST]) {
569  FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].irt, >=, fr_time_delta_from_sec(1));
570 #if 0
571  FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
572  FR_INTEGER_BOUND_CHECK("Accounting-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrc, >=, 0);
573  FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrd, >=, fr_time_delta_from_sec(0));
574 #endif
575 
576  FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].irt, <=, fr_time_delta_from_sec(3));
577  FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrt, <=, fr_time_delta_from_sec(30));
578  FR_INTEGER_BOUND_CHECK("Accounting-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrc, <=, 10);
579  FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
580  }
581 
582  /*
583  * Status-Server
584  */
585  if (inst->allowed[FR_RADIUS_CODE_STATUS_SERVER]) {
586  FR_TIME_DELTA_BOUND_CHECK("Status-Server.initial_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].irt, >=, fr_time_delta_from_sec(1));
587  FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrt, >=, fr_time_delta_from_sec(5));
588  FR_INTEGER_BOUND_CHECK("Status-Server.max_rtx_count", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrc, >=, 1);
589  FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_duration", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrd, >=, fr_time_delta_from_sec(5));
590 
591  FR_TIME_DELTA_BOUND_CHECK("Status-Server.initial_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].irt, <=, fr_time_delta_from_sec(3));
592  FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrt, <=, fr_time_delta_from_sec(30));
593  FR_INTEGER_BOUND_CHECK("Status-Server.max_rtx_count", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrc, <=, 10);
594  FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_duration", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrd, <=, fr_time_delta_from_sec(30));
595  }
596 
597  /*
598  * CoA
599  */
600  if (inst->allowed[FR_RADIUS_CODE_COA_REQUEST]) {
601  FR_TIME_DELTA_BOUND_CHECK("CoA-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].irt, >=, fr_time_delta_from_sec(1));
602  FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
603  FR_INTEGER_BOUND_CHECK("CoA-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrc, >=, 1);
604  FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrd, >=, fr_time_delta_from_sec(5));
605 
606  FR_TIME_DELTA_BOUND_CHECK("CoA-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].irt, <=, fr_time_delta_from_sec(3));
607  FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrt, <=, fr_time_delta_from_sec(60));
608  FR_INTEGER_BOUND_CHECK("CoA-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrc, <=, 10);
609  FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
610  }
611 
612  /*
613  * Disconnect
614  */
615  if (inst->allowed[FR_RADIUS_CODE_DISCONNECT_REQUEST]) {
616  FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].irt, >=, fr_time_delta_from_sec(1));
617  FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
618  FR_INTEGER_BOUND_CHECK("Disconnect-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrc, >=, 1);
619  FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd, >=, fr_time_delta_from_sec(5));
620 
621  FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].irt, <=, fr_time_delta_from_sec(3));
622  FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrt, <=, fr_time_delta_from_sec(30));
623  FR_INTEGER_BOUND_CHECK("Disconnect-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrc, <=, 10);
624  FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
625  }
626 
627 setup_io_submodule:
628  /*
629  * Get random Proxy-State identifier for this module.
630  */
631  inst->proxy_state = fr_rand();
632 
633  return 0;
634 }
635 
636 static int mod_detach(module_detach_ctx_t const *mctx)
637 {
638  rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
639 
640  talloc_free(inst->received_message_authenticator);
641  return 0;
642 }
643 
644 static int mod_load(void)
645 {
646  if (fr_radius_global_init() < 0) {
647  PERROR("Failed initialising protocol library");
648  return -1;
649  }
650  return 0;
651 }
652 
653 static void mod_unload(void)
654 {
656 }
657 
658 /*
659  * The module name should be the only globally exported symbol.
660  * That is, everything else should be 'static'.
661  *
662  * If the module needs to temporarily modify it's instantiation
663  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
664  * The server will then take care of ensuring that the module
665  * is single-threaded.
666  */
667 extern module_rlm_t rlm_radius;
669  .common = {
670  .magic = MODULE_MAGIC_INIT,
671  .name = "radius",
672  .inst_size = sizeof(rlm_radius_t),
674 
675  .onload = mod_load,
676  .unload = mod_unload,
677 
679  .detach = mod_detach
680  },
681  .method_group = {
682  .bindings = (module_method_binding_t[]){
683  { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_process },
685  },
686  }
687 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition: action.h:42
#define RCSID(id)
Definition: build.h:481
#define STRINGIFY(x)
Definition: build.h:195
#define UNUSED
Definition: build.h:313
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition: cf_parse.c:1474
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Definition: cf_parse.h:487
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition: cf_parse.h:310
#define cf_section_rule_push(_cs, _rule)
Definition: cf_parse.h:657
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition: cf_parse.h:297
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition: cf_parse.h:498
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:405
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
Definition: cf_parse.h:419
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition: cf_parse.h:420
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition: cf_parse.h:399
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:241
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
Common header for all CONF_* types.
Definition: cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:664
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1185
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1594
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:684
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition: cf_util.c:618
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1171
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define cf_parent(_cf)
Definition: cf_util.h:101
#define cf_log_warn(_cf, _fmt,...)
Definition: cf_util.h:290
#define CF_IDENT_ANY
Definition: cf_util.h:78
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:288
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
Definition: defs.h:33
@ FR_RADIUS_CODE_DISCONNECT_REQUEST
RFC3575/RFC5176 - Disconnect-Request.
Definition: defs.h:46
@ FR_RADIUS_CODE_MAX
Maximum possible protocol code.
Definition: defs.h:53
@ FR_RADIUS_CODE_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
Definition: defs.h:44
@ FR_RADIUS_CODE_COA_REQUEST
RFC3575/RFC5176 - CoA-Request.
Definition: defs.h:49
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
Definition: defs.h:36
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
fr_value_box_t const * value
Enum value (what name maps to).
Definition: dict.h:230
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition: dict_util.c:3395
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
Value of an enumerated attribute.
Definition: dict.h:226
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
if(rcode > 0)
Definition: fd_read.h:9
bool active
for dynamic clients
Definition: client.h:119
bool dynamic
Whether the client was dynamically defined.
Definition: client.h:118
Describes a host allowed to send packets to the server.
Definition: client.h:80
#define PERROR(_fmt,...)
Definition: log.h:228
#define RWARN(fmt,...)
Definition: log.h:297
int map_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map.
Definition: map.c:1014
talloc_free(reap)
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
Definition: compile.c:470
void * env_data
Per call environment data.
Definition: module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
void * rctx
Resume ctx that a module previously set.
Definition: module_ctx.h:45
module_instance_t * mi
Module instance to detach.
Definition: module_ctx.h:57
#define MODULE_CTX(_mi, _thread, _env_data, _rctx)
Wrapper to create a module_ctx_t as a compound literal.
Definition: module_ctx.h:128
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for detach calls.
Definition: module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic conf_parser_t func for loading drivers.
Definition: module_rlm.c:950
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:693
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition: pair.c:2981
static const conf_parser_t config[]
Definition: base.c:183
size_t fr_radius_require_ma_table_len
Definition: base.c:90
int fr_radius_global_init(void)
Definition: base.c:1217
void fr_radius_global_free(void)
Definition: base.c:1240
fr_table_num_sorted_t const fr_radius_require_ma_table[]
Definition: base.c:83
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition: base.c:112
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG_ENABLED()
Definition: radclient.h:49
#define RADIUS_MAX_ATTRIBUTES
Definition: radius.h:40
static rs_t * conf
Definition: radsniff.c:53
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
static conf_parser_t coa_config[]
Definition: rlm_radius.c:81
static conf_parser_t disconnect_config[]
Definition: rlm_radius.c:89
static int status_check_type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static int mod_detach(module_detach_ctx_t const *mctx)
Definition: rlm_radius.c:636
static int mod_load(void)
Definition: rlm_radius.c:644
static fr_dict_attr_t const * attr_packet_type
Definition: rlm_radius.c:153
static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Send packets outbound.
Definition: rlm_radius.c:395
static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static fr_dict_attr_t const * attr_chap_password
Definition: rlm_radius.c:152
static fr_dict_t const * dict_radius
Definition: rlm_radius.c:143
static fr_dict_attr_t const * attr_chap_challenge
Definition: rlm_radius.c:151
static conf_parser_t status_config[]
Definition: rlm_radius.c:73
fr_dict_attr_autoload_t rlm_radius_dict_attr[]
Definition: rlm_radius.c:157
static void mod_unload(void)
Definition: rlm_radius.c:653
static void mod_radius_signal(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
Definition: rlm_radius.c:338
static void radius_fixups(rlm_radius_t const *inst, request_t *request)
Do any RADIUS-layer fixups for proxying.
Definition: rlm_radius.c:360
static fr_dict_attr_t const * attr_proxy_state
Definition: rlm_radius.c:154
static conf_parser_t const type_interval_config[FR_RADIUS_CODE_MAX]
Definition: rlm_radius.c:134
static conf_parser_t auth_config[]
Definition: rlm_radius.c:57
module_rlm_t rlm_radius
Definition: rlm_radius.c:668
fr_dict_autoload_t rlm_radius_dict[]
Definition: rlm_radius.c:146
static int status_check_update_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static conf_parser_t const status_check_update_config[]
Definition: rlm_radius.c:45
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_radius.c:460
static conf_parser_t const status_check_config[]
Definition: rlm_radius.c:38
static conf_parser_t const module_config[]
Definition: rlm_radius.c:101
static conf_parser_t acct_config[]
Definition: rlm_radius.c:65
struct rlm_radius_s rlm_radius_t
Definition: rlm_radius.h:36
unlang_module_signal_t signal
Send a signal to an IO module.
Definition: rlm_radius.h:87
Public structure describing an I/O path for an outgoing socket.
Definition: rlm_radius.h:84
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1302
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition: section.h:40
char const * name
Instance name e.g. user_database.
Definition: module.h:335
static module_thread_instance_t * module_thread(module_instance_t const *mi)
Retrieve module/thread specific instance for a module.
Definition: module.h:481
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
void * data
Thread specific instance data.
Definition: module.h:352
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition: module.h:151
Named methods exported by a module.
Definition: module.h:173
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition: pair.h:37
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
fr_signal_t
Definition: signal.h:48
fr_client_t * client_from_request(request_t *request)
Search up a list of requests trying to locate one which has a client.
Definition: client.c:1112
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition: module.c:419
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
#define talloc_get_type_abort_const
Definition: talloc.h:282
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:590
#define fr_time_delta_ispos(_a)
Definition: time.h:290
conf_parser_t const trunk_config[]
Config parser definitions to populate a trunk_conf_t.
Definition: trunk.c:312
static fr_slen_t head
Definition: xlat.h:406
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition: pair.h:628
static fr_slen_t parent
Definition: pair.h:851
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:997