The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.c
Go to the documentation of this file.
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: 62f561c12cac67b51ec98695789b7f46a9367675 $
19  * @file src/process/radius/base.c
20  * @brief RADIUS process module
21  *
22  * @copyright 2021 The FreeRADIUS server project.
23  * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
24  */
25 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
26 
27 #include <freeradius-devel/radius/radius.h>
28 
29 #include <freeradius-devel/server/main_config.h>
30 #include <freeradius-devel/server/module.h>
31 #include <freeradius-devel/server/pair.h>
32 #include <freeradius-devel/server/protocol.h>
33 #include <freeradius-devel/server/state.h>
34 #include <freeradius-devel/server/log.h>
35 #include <freeradius-devel/unlang/xlat.h>
36 
37 #include <freeradius-devel/unlang/module.h>
38 #include <freeradius-devel/unlang/interpret.h>
39 #include <freeradius-devel/unlang/xlat_func.h>
40 
41 #include <freeradius-devel/util/debug.h>
42 #include <freeradius-devel/util/pair.h>
43 #include <freeradius-devel/util/value.h>
44 
45 static fr_dict_t const *dict_freeradius;
46 static fr_dict_t const *dict_radius;
47 
50  { .out = &dict_freeradius, .proto = "freeradius" },
51  { .out = &dict_radius, .proto = "radius" },
52  { NULL }
53 };
54 
59 
63 static fr_dict_attr_t const *attr_state;
69 
72  { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
73  { .out = &attr_module_failure_message, .name = "Module-Failure-Message", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
74  { .out = &attr_module_success_message, .name = "Module-Success-Message", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
75  { .out = &attr_stripped_user_name, .name = "Stripped-User-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
76 
77  { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
78  { .out = &attr_proxy_state, .name = "Proxy-State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
79  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
80  { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
81  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
82  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
83 
84  { .out = &attr_original_packet_code, .name = "Extended-Attribute-1.Original-Packet-Code", .type = FR_TYPE_UINT32, .dict = &dict_radius },
85  { .out = &attr_error_cause, .name = "Error-Cause", .type = FR_TYPE_UINT32, .dict = &dict_radius },
86 
87  { .out = &attr_event_timestamp, .name = "Event-Timestamp", .type = FR_TYPE_DATE, .dict = &dict_radius },
88 
89  { NULL }
90 };
91 
94 
97  { .out = &enum_auth_type_accept, .name = "Accept", .attr = &attr_auth_type },
98  { .out = &enum_auth_type_reject, .name = "Reject", .attr = &attr_auth_type },
99  { NULL }
100 };
101 
102 /*
103  * RADIUS state machine configuration
104  */
105 typedef struct {
106  uint64_t nothing; // so that "access_request" isn't at offset 0
107 
112 
115 
117 
121 
125 
127  CONF_SECTION *protocol_error; /* @todo - allow protocol error as a reject reply? */
128 
133 
134 typedef struct {
135  fr_time_delta_t session_timeout; //!< Maximum time between the last response and next request.
136  uint32_t max_session; //!< Maximum ongoing session allowed.
137 
138  uint8_t state_server_id; //!< Sets a specific byte in the state to allow the
139  //!< authenticating server to be identified in packet
140  //!<captures.
141 
142  fr_state_tree_t *state_tree; //!< State tree to link multiple requests/responses.
144 
145 typedef struct {
146  CONF_SECTION *server_cs; //!< Our virtual server.
147  process_radius_sections_t sections; //!< Pointers to various config sections
148  ///< we need to execute.
149  process_radius_auth_t auth; //!< Authentication configuration.
151 
152 /** Records fields from the original request so we have a known good copy
153  */
154 typedef struct {
155  fr_value_box_list_head_t proxy_state; //!< These need to be copied into the response in exactly
156  ///< the same order as they were added.
158 
159 #define FR_RADIUS_PROCESS_CODE_VALID(_x) (FR_RADIUS_PACKET_CODE_VALID(_x) || (_x == FR_RADIUS_CODE_DO_NOT_RESPOND))
160 
161 #define PROCESS_PACKET_TYPE fr_radius_packet_code_t
162 #define PROCESS_CODE_MAX FR_RADIUS_CODE_MAX
163 #define PROCESS_CODE_DO_NOT_RESPOND FR_RADIUS_CODE_DO_NOT_RESPOND
164 #define PROCESS_PACKET_CODE_VALID FR_RADIUS_PROCESS_CODE_VALID
165 #define PROCESS_INST process_radius_t
166 #define PROCESS_CODE_DYNAMIC_CLIENT FR_RADIUS_CODE_ACCESS_ACCEPT
167 #include <freeradius-devel/server/process.h>
168 
169 static const conf_parser_t session_config[] = {
170  { FR_CONF_OFFSET("timeout", process_radius_auth_t, session_timeout), .dflt = "15" },
171  { FR_CONF_OFFSET("max", process_radius_auth_t, max_session), .dflt = "4096" },
172  { FR_CONF_OFFSET("state_server_id", process_radius_auth_t, state_server_id) },
173 
175 };
176 
177 static const conf_parser_t auth_config[] = {
178  { FR_CONF_POINTER("session", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) session_config },
179 
181 };
182 
183 static const conf_parser_t config[] = {
184  { FR_CONF_POINTER("Access-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) auth_config,
185  .offset = offsetof(process_radius_t, auth), },
186 
188 };
189 
190 /*
191  * Debug the packet if requested.
192  */
193 static void radius_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
194 {
195 #ifdef WITH_IFINDEX_NAME_RESOLUTION
196  char if_name[IFNAMSIZ];
197 #endif
198 
199  if (!packet) return;
200  if (!RDEBUG_ENABLED) return;
201 
202  log_request(L_DBG, L_DBG_LVL_1, request, __FILE__, __LINE__, "%s %s ID %d from %s%pV%s:%i to %s%pV%s:%i "
203 #ifdef WITH_IFINDEX_NAME_RESOLUTION
204  "%s%s%s"
205 #endif
206  "",
207  received ? "Received" : "Sending",
208  fr_radius_packet_name[packet->code],
209  packet->id,
210  packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "",
211  fr_box_ipaddr(packet->socket.inet.src_ipaddr),
212  packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "",
213  packet->socket.inet.src_port,
214  packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "",
215  fr_box_ipaddr(packet->socket.inet.dst_ipaddr),
216  packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "",
217  packet->socket.inet.dst_port
218 #ifdef WITH_IFINDEX_NAME_RESOLUTION
219  , packet->socket.inet.ifindex ? "via " : "",
220  packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "",
221  packet->socket.inet.ifindex ? " " : ""
222 #endif
223  );
224 
225  if (received || request->parent) {
226  log_request_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
227  } else {
228  log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
229  }
230 }
231 
232 /** Keep a copy of some attributes to keep them from being tamptered with
233  *
234  */
235 static inline CC_HINT(always_inline)
237 {
238  fr_pair_t *proxy_state;
240 
241  /*
242  * Don't bother allocing the struct if there's no proxy state to store
243  */
244  proxy_state = fr_pair_find_by_da(&request->request_pairs, NULL, attr_proxy_state);
245  if (!proxy_state) return 0;
246 
248  fr_value_box_list_init(&rctx->proxy_state);
249 
250  /*
251  * We don't use fr_pair_list_copy_by_da, to avoid doing the lookup for
252  * the first proxy-state attr again.
253  */
254  do {
255  fr_value_box_t *proxy_state_value;
256 
257  MEM((proxy_state_value = fr_value_box_acopy(rctx, &proxy_state->data)));
258  fr_value_box_list_insert_tail(&rctx->proxy_state, proxy_state_value);
259  } while ((proxy_state = fr_pair_find_by_da(&request->request_pairs, proxy_state, attr_proxy_state)));
260 
261  return rctx;
262 }
263 
264 static inline CC_HINT(always_inline)
266 {
267  if (!rctx) return;
268 
269  /*
270  * Proxy-State is a link-level signal between RADIUS
271  * client and server. RFC 2865 Section 5.33 says that
272  * Proxy-State is an opaque field, and implementations
273  * most not examine it, interpret it, or assign it any
274  * meaning. Implementations must also copy all Proxy-State
275  * from the request to the reply.
276  *
277  * The rlm_radius module already deletes any Proxy-State
278  * from the reply before appending the proxy reply to the
279  * current reply.
280  *
281  * If any policy creates Proxy-State, that could affect
282  * individual RADIUS links (perhaps), and that would be
283  * wrong. As such, we nuke any nonsensical Proxy-State
284  * added by policies or errant modules, and instead just
285  * do exactly what the RFCs require us to do. No more.
286  */
287  fr_pair_delete_by_da(&request->reply_pairs, attr_proxy_state);
288 
289  RDEBUG3("Adding Proxy-State attributes from request");
290  RINDENT();
291  fr_value_box_list_foreach(&rctx->proxy_state, proxy_state_value) {
292  fr_pair_t *vp;
293 
294  MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_proxy_state));
295  fr_value_box_copy(vp, &vp->data, proxy_state_value);
296  fr_pair_append(&request->reply_pairs, vp);
297  RDEBUG3("&reply.%pP", vp);
298  }
299  REXDENT();
300 }
301 
302 /** A wrapper around recv generic which stores fields from the request
303  */
304 RECV(generic_radius_request)
305 {
306  module_ctx_t our_mctx = *mctx;
307 
308  fr_assert_msg(!mctx->rctx, "rctx not expected here");
309  our_mctx.rctx = radius_request_pairs_store(request);
310  mctx = &our_mctx; /* Our mutable mctx */
311 
312  return CALL_RECV(generic);
313 }
314 
315 /** A wrapper around send generic which restores fields
316  *
317  */
318 RESUME(generic_radius_response)
319 {
320  if (mctx->rctx) radius_request_pairs_to_reply(request, talloc_get_type_abort(mctx->rctx, process_radius_request_pairs_t));
321 
322  return CALL_RESUME(send_generic);
323 }
324 
325 RECV(access_request)
326 {
328 
329  /*
330  * Only reject if the state has already been thawed.
331  * It could be that the state value wasn't intended
332  * for us, and we're just proxying upstream.
333  */
334  if (fr_state_to_request(inst->auth.state_tree, request) < 0) {
335  return CALL_SEND_TYPE(FR_RADIUS_CODE_ACCESS_REJECT);
336  }
337 
338  return CALL_RECV(generic_radius_request);
339 }
340 
341 RESUME(auth_type);
342 
343 RESUME(access_request)
344 {
345  rlm_rcode_t rcode = *p_result;
346  fr_pair_t *vp;
347  CONF_SECTION *cs;
348  fr_dict_enum_value_t const *dv;
349  fr_process_state_t const *state;
351 
353 
355 
356  /*
357  * See if the return code from "recv Access-Request" says we reject, or continue.
358  */
359  UPDATE_STATE(packet);
360 
361  request->reply->code = state->packet_type[rcode];
362  if (!request->reply->code) request->reply->code = state->default_reply;
363 
364  /*
365  * Something set reject, we're done.
366  */
367  if (request->reply->code == FR_RADIUS_CODE_ACCESS_REJECT) {
368  RDEBUG("The 'recv Access-Request' section returned %s - rejecting the request",
369  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
370 
371  send_reply:
372  UPDATE_STATE(reply);
373 
374  fr_assert(state->send != NULL);
375  return CALL_SEND_STATE(state);
376  }
377 
378  if (request->reply->code) {
379  goto send_reply;
380  }
381 
382  /*
383  * A policy _or_ a module can hard-code the reply.
384  */
385  if (!request->reply->code) {
386  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
387  if (vp && FR_RADIUS_PROCESS_CODE_VALID(vp->vp_uint32)) {
388  request->reply->code = vp->vp_uint32;
389  goto send_reply;
390  }
391  }
392 
393  /*
394  * Run authenticate foo { ... }
395  *
396  * If we can't find Auth-Type, OR if we can't find
397  * Auth-Type = foo, then it's a reject.
398  */
399  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_auth_type);
400  if (!vp) {
401  RDEBUG("No 'Auth-Type' attribute found, cannot authenticate the user - rejecting the request");
402 
403  reject:
404  request->reply->code = FR_RADIUS_CODE_ACCESS_REJECT;
405  goto send_reply;
406  }
407 
408  dv = fr_dict_enum_by_value(vp->da, &vp->data);
409  if (!dv) {
410  RDEBUG("Invalid value for 'Auth-Type' attribute, cannot authenticate the user - rejecting the request");
411 
412  goto reject;
413  }
414 
415  /*
416  * The magic Auth-Type Accept value
417  * which means skip the authenticate
418  * section.
419  *
420  * And Reject means always reject. Tho the admin should
421  * just return "reject" from the section.
422  */
424  request->reply->code = FR_RADIUS_CODE_ACCESS_ACCEPT;
425  goto send_reply;
426 
427  } else if (fr_value_box_cmp(enum_auth_type_reject, dv->value) == 0) {
428  request->reply->code = FR_RADIUS_CODE_ACCESS_REJECT;
429  goto send_reply;
430  }
431 
432  cs = cf_section_find(inst->server_cs, "authenticate", dv->name);
433  if (!cs) {
434  RDEBUG2("No 'authenticate %s { ... }' section found - rejecting the request", dv->name);
435  goto reject;
436  }
437 
438  /*
439  * Run the "Authenticate = foo" section.
440  *
441  * And continue with sending the generic reply.
442  */
443  RDEBUG("Running 'authenticate %s' from file %s", cf_section_name2(cs), cf_filename(cs));
444  return unlang_module_yield_to_section(p_result, request,
445  cs, RLM_MODULE_NOOP, resume_auth_type,
446  NULL, 0, mctx->rctx);
447 }
448 
449 RESUME(auth_type)
450 {
451  static const fr_process_rcode_t auth_type_rcode = {
460  };
461 
462  rlm_rcode_t rcode = *p_result;
463  fr_pair_t *vp;
464  fr_process_state_t const *state;
465 
467 
469 
470  if (auth_type_rcode[rcode] == FR_RADIUS_CODE_DO_NOT_RESPOND) {
471  request->reply->code = auth_type_rcode[rcode];
472  UPDATE_STATE(reply);
473 
474  RDEBUG("The 'authenticate' section returned %s - not sending a response",
475  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
476 
477  fr_assert(state->send != NULL);
478  return state->send(p_result, mctx, request);
479  }
480 
481  /*
482  * Most cases except handled...
483  */
484  if (auth_type_rcode[rcode]) request->reply->code = auth_type_rcode[rcode];
485 
486  switch (request->reply->code) {
487  case 0:
488  RDEBUG("No reply code was set. Forcing to Access-Reject");
489  request->reply->code = FR_RADIUS_CODE_ACCESS_REJECT;
490  FALL_THROUGH;
491 
492  /*
493  * Print complaints before running "send Access-Reject"
494  */
496  RDEBUG2("Failed to authenticate the user");
497 
498  /*
499  * Maybe the shared secret is wrong?
500  */
501  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
502  if (vp) {
503  if (RDEBUG_ENABLED2) {
504  uint8_t const *p;
505 
506  p = (uint8_t const *) vp->vp_strvalue;
507  while (*p) {
508  int size;
509 
510  size = fr_utf8_char(p, -1);
511  if (!size) {
512  RWDEBUG("Unprintable characters in the password. "
513  "Double-check the shared secret on the server "
514  "and the NAS!");
515  break;
516  }
517  p += size;
518  }
519  }
520  }
521  break;
522 
523  /*
524  * Access-Challenge sections require a State. If there is
525  * none, create one here. This is so that the State
526  * attribute is accessible in the "send Access-Challenge"
527  * section.
528  */
530  if ((vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_state)) != NULL) {
531  uint8_t buffer[16];
532 
533  fr_rand_buffer(buffer, sizeof(buffer));
534 
536  fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
537  }
538  break;
539 
540  default:
541  break;
542 
543  }
544  UPDATE_STATE(reply);
545 
546  fr_assert(state->send != NULL);
547  return state->send(p_result, mctx, request);
548 }
549 
550 RESUME(access_accept)
551 {
552  fr_pair_t *vp;
554 
556 
557  /*
558  * Check that there is a name which can be used to
559  * identify the user. The configuration depends on
560  * User-Name or Stripped-User-Name existing, and being
561  * (mostly) unique to that user.
562  */
563  if (!request->parent &&
564  ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name)) != NULL) &&
565  (vp->vp_strvalue[0] == '@') &&
566  !fr_pair_find_by_da(&request->request_pairs, NULL, attr_stripped_user_name)) {
567  RWDEBUG("User-Name is anonymized, and no Stripped-User-Name exists.");
568  RWDEBUG("It may be difficult or impossible to identify the user.");
569  RWDEBUG("Please update Stripped-User-Name with information which identifies the user.");
570  }
571 
572  fr_state_discard(inst->auth.state_tree, request);
573  radius_request_pairs_to_reply(request, mctx->rctx);
575 }
576 
577 RESUME(access_reject)
578 {
580 
582 
583  fr_state_discard(inst->auth.state_tree, request);
584  radius_request_pairs_to_reply(request, mctx->rctx);
586 }
587 
588 RESUME(access_challenge)
589 {
591 
593 
594  /*
595  * Cache the state context, unless this is a subrequest.
596  * Subrequest state context will be handled by the caller.
597  *
598  * If this fails, don't respond to the request.
599  */
600  if (!request->parent && fr_request_to_state(inst->auth.state_tree, request) < 0) {
601  return CALL_SEND_TYPE(FR_RADIUS_CODE_DO_NOT_RESPOND);
602  }
603 
604  fr_assert(request->reply->code == FR_RADIUS_CODE_ACCESS_CHALLENGE);
605  radius_request_pairs_to_reply(request, mctx->rctx);
607 }
608 
609 /** A wrapper around recv generic which stores fields from the request
610  */
611 RECV(accounting_request)
612 {
613  module_ctx_t our_mctx = *mctx;
614  fr_pair_t *acct_delay, *event_timestamp;
615 
616  fr_assert_msg(!mctx->rctx, "rctx not expected here");
617  our_mctx.rctx = radius_request_pairs_store(request);
618  mctx = &our_mctx; /* Our mutable mctx */
619 
620  /*
621  * Acct-Delay-Time is horrific. Its existence in a packet means that any retransmissions can't
622  * be retransmissions! Instead, we have to send a brand new packet each time. This rewriting is
623  * expensive, causes ID churn, over-allocation of IDs, and makes it more difficult to discover
624  * end-to-end failures.
625  *
626  * As a result, we delete Acct-Delay-Time, and replace it with Event-Timestamp.
627  */
628  event_timestamp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
629  if (!event_timestamp) {
630  MEM(event_timestamp = fr_pair_afrom_da(request->request_ctx, attr_event_timestamp));
631  fr_pair_append(&request->request_pairs, event_timestamp);
632  event_timestamp->vp_date = fr_time_to_unix_time(request->packet->timestamp);
633 
634  acct_delay = fr_pair_find_by_da(&request->request_pairs, NULL, attr_event_timestamp);
635  if (acct_delay) {
636  if (acct_delay->vp_uint32 < ((365 * 86400))) {
637  event_timestamp->vp_date = fr_unix_time_sub_time_delta(event_timestamp->vp_date, fr_time_delta_from_sec(acct_delay->vp_uint32));
638 
639  RDEBUG("Accounting-Request packet contains %pP. Creating %pP",
640  acct_delay, event_timestamp);
641  }
642  } else {
643  RDEBUG("Accounting-Request packet is missing Event-Timestamp. Adding it to packet as %pP.", event_timestamp);
644  }
645  }
646 
647  return CALL_RECV(generic);
648 }
649 
650 RESUME(acct_type)
651 {
652  static const fr_process_rcode_t acct_type_rcode = {
658  };
659 
660  rlm_rcode_t rcode = *p_result;
661  fr_process_state_t const *state;
662 
664 
666  fr_assert(FR_RADIUS_PROCESS_CODE_VALID(request->reply->code));
667 
668  if (acct_type_rcode[rcode]) {
669  fr_assert(acct_type_rcode[rcode] == FR_RADIUS_CODE_DO_NOT_RESPOND);
670 
671  request->reply->code = acct_type_rcode[rcode];
672  UPDATE_STATE(reply);
673 
674  RDEBUG("The 'accounting' section returned %s - not sending a response",
675  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
676 
677  fr_assert(state->send != NULL);
678  return state->send(p_result, mctx, request);
679  }
680 
681  request->reply->code = FR_RADIUS_CODE_ACCOUNTING_RESPONSE;
682  UPDATE_STATE(reply);
683 
684  fr_assert(state->send != NULL);
685  return state->send(p_result, mctx, request);
686 }
687 
688 RESUME(accounting_request)
689 {
690  rlm_rcode_t rcode = *p_result;
691  fr_pair_t *vp;
692  CONF_SECTION *cs;
693  fr_dict_enum_value_t const *dv;
694  fr_process_state_t const *state;
696 
698 
700 
701  UPDATE_STATE(packet);
702  fr_assert(state->packet_type[rcode] != 0);
703 
704  request->reply->code = state->packet_type[rcode];
705  UPDATE_STATE_CS(reply);
706 
707  if (request->reply->code == FR_RADIUS_CODE_DO_NOT_RESPOND) {
708  RDEBUG("The 'recv Accounting-Request' section returned %s - not sending a response",
709  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
710 
711  send_reply:
712  fr_assert(state->send != NULL);
713  return CALL_SEND_STATE(state);
714  }
715 
716  /*
717  * Run accounting foo { ... }
718  */
719  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_acct_status_type);
720  if (!vp) goto send_reply;
721 
722  dv = fr_dict_enum_by_value(vp->da, &vp->data);
723  if (!dv) goto send_reply;
724 
725  cs = cf_section_find(inst->server_cs, "accounting", dv->name);
726  if (!cs) {
727  RDEBUG2("No 'accounting %s { ... }' section found - skipping...", dv->name);
728  goto send_reply;
729  }
730 
731  /*
732  * Run the "Acct-Status-Type = foo" section.
733  *
734  * And continue with sending the generic reply.
735  */
736  return unlang_module_yield_to_section(p_result, request,
737  cs, RLM_MODULE_NOOP, resume_acct_type,
738  NULL, 0, mctx->rctx);
739 }
740 
741 #if 0
742 // @todo - send canned responses like in v3?
743 RECV(status_server)
744 {
746 }
747 
748 RESUME(status_server)
749 {
751 }
752 #endif
753 
754 RESUME(protocol_error)
755 {
756  fr_pair_t *vp;
757 
759 
760  fr_assert(FR_RADIUS_PACKET_CODE_VALID(request->reply->code));
761 
762  /*
763  * https://tools.ietf.org/html/rfc7930#section-4
764  */
765  vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_original_packet_code);
766  if (!vp) {
767  vp = fr_pair_afrom_da(request->reply_ctx, attr_original_packet_code);
768  if (vp) {
769  vp->vp_uint32 = request->packet->code;
770  fr_pair_append(&request->reply_pairs, vp);
771  }
772  }
773 
774  /*
775  * If there's no Error-Cause, then include a generic 404.
776  */
777  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_error_cause);
778  if (!vp) {
779  vp = fr_pair_afrom_da(request->reply_ctx, attr_error_cause);
780  if (vp) {
781  vp->vp_uint32 = FR_ERROR_CAUSE_VALUE_INVALID_REQUEST;
782  fr_pair_append(&request->reply_pairs, vp);
783  }
784  }
785 
786  /*
787  * And do the generic processing after running a "send" section.
788  */
789  return CALL_RESUME(send_generic);
790 }
791 
792 static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
793 {
794  fr_process_state_t const *state;
795 
797 
799 
800  request->component = "radius";
801  request->module = NULL;
802  fr_assert(request->dict == dict_radius);
803 
804  fr_assert(FR_RADIUS_PACKET_CODE_VALID(request->packet->code));
805 
806  UPDATE_STATE(packet);
807 
808  if (!state->recv) {
809  REDEBUG("Invalid packet type (%u)", request->packet->code);
811  }
812 
813  radius_packet_debug(request, request->packet, &request->request_pairs, true);
814 
815  if (unlikely(request_is_dynamic_client(request))) {
816  return new_client(p_result, mctx, request);
817  }
818 
819  return state->recv(p_result, mctx, request);
820 }
821 
823  { .required = true, .single = true, .type = FR_TYPE_OCTETS },
825 };
826 
827 /** Validates a request against a know shared secret
828  *
829  * Designed for the specific purpose of verifying dynamic clients
830  * against a know shared secret.
831  *
832  * Example:
833 @verbatim
834 %radius.secret.verify(<secret>)
835 @endverbatim
836  *
837  * @ingroup xlat_functions
838  */
840  request_t *request, fr_value_box_list_t *args)
841 {
842  fr_value_box_t *secret, *vb;
843  int ret;
844  bool require_message_authenticator = false;
845 
846  XLAT_ARGS(args, &secret);
847 
848  if (request->dict != dict_radius) return XLAT_ACTION_FAIL;
849 
850  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
851 
852  /*
853  * Only Access-Requests require a Message-Authenticator.
854  * All the other packet types are signed using the
855  * authenticator field.
856  */
857  if (request->packet->code == FR_RADIUS_CODE_ACCESS_REQUEST) require_message_authenticator = true;
858 
859  ret = fr_radius_verify(request->packet->data, NULL, secret->vb_octets, secret->vb_length, require_message_authenticator, false);
860  switch (ret) {
861  case 0:
862  vb->vb_bool = true;
863  break;
864 
865  case -1:
866  RPEDEBUG("Failed verifying secret");
867  return XLAT_ACTION_FAIL;
868 
869  case -2:
870  RPDEBUG2("Provided secret was not used to sign this packet");
871  vb->vb_bool = false;
872  break;
873  }
874  fr_dcursor_append(out, vb);
875 
876  return XLAT_ACTION_DONE;
877 }
878 
879 static int mod_instantiate(module_inst_ctx_t const *mctx)
880 {
881  process_radius_t *inst = talloc_get_type_abort(mctx->mi->data, process_radius_t);
882 
883  inst->server_cs = cf_item_to_section(cf_parent(mctx->mi->conf));
884 
885  inst->auth.state_tree = fr_state_tree_init(inst, attr_state, main_config->spawn_workers, inst->auth.max_session,
886  inst->auth.session_timeout, inst->auth.state_server_id,
887  fr_hash_string(cf_section_name2(inst->server_cs)));
888 
889  return 0;
890 }
891 
892 static int mod_bootstrap(module_inst_ctx_t const *mctx)
893 {
894  CONF_SECTION *server_cs = cf_item_to_section(cf_parent(mctx->mi->conf));
895 
896  if (virtual_server_section_attribute_define(server_cs, "authenticate", attr_auth_type) < 0) return -1;
897 
898  return 0;
899 }
900 
901 static int mod_load(void)
902 {
903  xlat_t *xlat;
904 
905  if (unlikely(!(xlat = xlat_func_register(NULL, "radius.secret.verify", xlat_func_radius_secret_verify,
906  FR_TYPE_BOOL)))) return -1;
907 
909 
910  return 0;
911 }
912 
913 static void mod_unload(void)
914 {
915  xlat_func_unregister("radius.secret.verify");
916 }
917 
918 /*
919  * rcodes not listed under a packet_type
920  * mean that the packet code will not be
921  * changed.
922  */
923 static fr_process_state_t const process_state[] = {
925  .packet_type = {
931  },
932  .rcode = RLM_MODULE_NOOP,
933  .recv = recv_access_request,
934  .resume = resume_access_request,
935  .section_offset = offsetof(process_radius_sections_t, access_request),
936  },
938  .packet_type = {
943  },
944  .rcode = RLM_MODULE_NOOP,
945  .send = send_generic,
946  .resume = resume_access_accept,
947  .section_offset = offsetof(process_radius_sections_t, access_accept),
948  },
950  .packet_type = {
955  },
956  .rcode = RLM_MODULE_NOOP,
957  .send = send_generic,
958  .resume = resume_access_reject,
959  .section_offset = offsetof(process_radius_sections_t, access_reject),
960  },
962  .packet_type = {
967  },
968  .rcode = RLM_MODULE_NOOP,
969  .send = send_generic,
970  .resume = resume_access_challenge,
971  .section_offset = offsetof(process_radius_sections_t, access_challenge),
972  },
973 
975  .packet_type = {
980 
986  },
987  .rcode = RLM_MODULE_NOOP,
988  .recv = recv_accounting_request,
989  .resume = resume_accounting_request,
990  .section_offset = offsetof(process_radius_sections_t, accounting_request),
991  },
993  .packet_type = {
999  },
1000  .rcode = RLM_MODULE_NOOP,
1001  .send = send_generic,
1002  .resume = resume_generic_radius_response,
1003  .section_offset = offsetof(process_radius_sections_t, accounting_response),
1004  },
1005  [ FR_RADIUS_CODE_STATUS_SERVER ] = { /* @todo - negotiation, stats, etc. */
1006  .packet_type = {
1009 
1016  },
1017  .rcode = RLM_MODULE_NOOP,
1018  .recv = recv_generic,
1019  .resume = resume_recv_generic,
1020  .section_offset = offsetof(process_radius_sections_t, status_server),
1021  },
1023  .packet_type = {
1028 
1033  },
1034  .rcode = RLM_MODULE_NOOP,
1035  .recv = recv_generic_radius_request,
1036  .resume = resume_recv_generic,
1037  .section_offset = offsetof(process_radius_sections_t, coa_request),
1038  },
1039  [ FR_RADIUS_CODE_COA_ACK ] = {
1040  .packet_type = {
1045  },
1046  .rcode = RLM_MODULE_NOOP,
1047  .send = send_generic,
1048  .resume = resume_generic_radius_response,
1049  .section_offset = offsetof(process_radius_sections_t, coa_ack),
1050  },
1051  [ FR_RADIUS_CODE_COA_NAK ] = {
1052  .packet_type = {
1057  },
1058  .rcode = RLM_MODULE_NOOP,
1059  .send = send_generic,
1060  .resume = resume_generic_radius_response,
1061  .section_offset = offsetof(process_radius_sections_t, coa_nak),
1062  },
1064  .packet_type = {
1069 
1074  },
1075  .rcode = RLM_MODULE_NOOP,
1076  .recv = recv_generic,
1077  .resume = resume_recv_generic,
1078  .section_offset = offsetof(process_radius_sections_t, disconnect_request),
1079  },
1081  .packet_type = {
1086  },
1087  .rcode = RLM_MODULE_NOOP,
1088  .send = send_generic,
1089  .resume = resume_generic_radius_response,
1090  .section_offset = offsetof(process_radius_sections_t, disconnect_ack),
1091  },
1093  .packet_type = {
1098  },
1099  .rcode = RLM_MODULE_NOOP,
1100  .send = send_generic,
1101  .resume = resume_generic_radius_response,
1102  .section_offset = offsetof(process_radius_sections_t, disconnect_nak),
1103  },
1104  [ FR_RADIUS_CODE_PROTOCOL_ERROR ] = { /* @todo - fill out required fields */
1105  .packet_type = {
1110  },
1111  .rcode = RLM_MODULE_NOOP,
1112  .send = send_generic,
1113  .resume = resume_protocol_error,
1114  .section_offset = offsetof(process_radius_sections_t, protocol_error),
1115  },
1117  .packet_type = {
1122 
1128  },
1129  .rcode = RLM_MODULE_NOOP,
1130  .send = send_generic,
1131  .resume = resume_send_generic,
1132  .section_offset = offsetof(process_radius_sections_t, do_not_respond),
1133  }
1134 };
1135 
1137  {
1138  .section = SECTION_NAME("recv", "Access-Request"),
1139  .actions = &mod_actions_authorize,
1140  .offset = PROCESS_CONF_OFFSET(access_request),
1141  },
1142  {
1143  .section = SECTION_NAME("send", "Access-Accept"),
1144  .actions = &mod_actions_postauth,
1145  .offset = PROCESS_CONF_OFFSET(access_accept),
1146  },
1147  {
1148  .section = SECTION_NAME("send", "Access-Challenge"),
1149  .actions = &mod_actions_postauth,
1150  .offset = PROCESS_CONF_OFFSET(access_challenge),
1151  },
1152  {
1153  .section = SECTION_NAME("send", "Access-Reject"),
1154  .actions = &mod_actions_postauth,
1155  .offset = PROCESS_CONF_OFFSET(access_reject),
1156  },
1157 
1158  {
1159  .section = SECTION_NAME("recv", "Accounting-Request"),
1160  .actions = &mod_actions_preacct,
1161  .offset = PROCESS_CONF_OFFSET(accounting_request),
1162  },
1163  {
1164  .section = SECTION_NAME("send", "Accounting-Response"),
1165  .actions = &mod_actions_accounting,
1166  .offset = PROCESS_CONF_OFFSET(accounting_response),
1167  },
1168 
1169  {
1170  .section = SECTION_NAME("recv", "Status-Server"),
1171  .actions = &mod_actions_authorize,
1172  .offset = PROCESS_CONF_OFFSET(status_server),
1173  },
1174  {
1175  .section = SECTION_NAME("recv", "CoA-Request"),
1176  .actions = &mod_actions_authorize,
1177  .offset = PROCESS_CONF_OFFSET(coa_request),
1178  },
1179  {
1180  .section = SECTION_NAME("send", "CoA-ACK"),
1181  .actions = &mod_actions_postauth,
1182  .offset = PROCESS_CONF_OFFSET(coa_ack),
1183  },
1184  {
1185  .section = SECTION_NAME("send", "CoA-NAK"),
1186  .actions = &mod_actions_authorize,
1187  .offset = PROCESS_CONF_OFFSET(coa_nak),
1188  },
1189  {
1190  .section = SECTION_NAME("recv", "Disconnect-Request"),
1191  .actions = &mod_actions_authorize,
1192  .offset = PROCESS_CONF_OFFSET(disconnect_request),
1193  },
1194  {
1195  .section = SECTION_NAME("send", "Disconnect-ACK"),
1196  .actions = &mod_actions_postauth,
1197  .offset = PROCESS_CONF_OFFSET(disconnect_ack),
1198  },
1199  {
1200  .section = SECTION_NAME("send", "Disconnect-NAK"),
1201  .actions = &mod_actions_postauth,
1202  .offset = PROCESS_CONF_OFFSET(disconnect_nak),
1203  },
1204  {
1205  .section = SECTION_NAME("send", "Protocol-Error"),
1206  .actions = &mod_actions_postauth,
1207  .offset = PROCESS_CONF_OFFSET(protocol_error),
1208  },
1209  {
1210  .section = SECTION_NAME("send", "Do-Not-Respond"),
1211  .actions = &mod_actions_postauth,
1212  .offset = PROCESS_CONF_OFFSET(do_not_respond),
1213  },
1214  {
1215  .section = SECTION_NAME("authenticate", CF_IDENT_ANY),
1216  .actions = &mod_actions_authenticate
1217  },
1218  {
1219  .section = SECTION_NAME("accounting", CF_IDENT_ANY),
1220  .actions = &mod_actions_authenticate
1221  },
1222 
1223  DYNAMIC_CLIENT_SECTIONS,
1224 
1226 };
1227 
1230  .common = {
1231  .magic = MODULE_MAGIC_INIT,
1232  .name = "radius",
1233  .config = config,
1234  .inst_size = sizeof(process_radius_t),
1235 
1236  .onload = mod_load,
1237  .unload = mod_unload,
1238  .bootstrap = mod_bootstrap,
1240  },
1241  .process = mod_process,
1242  .compile_list = compile_list,
1243  .dict = &dict_radius,
1244 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
static int const char char buffer[256]
Definition: acutest.h:574
while(1)
Definition: acutest.h:856
va_list args
Definition: acutest.h:770
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#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
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition: cf_parse.h:399
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:1028
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1185
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:684
#define cf_parent(_cf)
Definition: cf_util.h:101
#define cf_filename(_cf)
Definition: cf_util.h:107
#define CF_IDENT_ANY
Definition: cf_util.h:78
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:406
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:210
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
Definition: defs.h:43
@ 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_DO_NOT_RESPOND
Special rcode to indicate we will not respond.
Definition: defs.h:54
@ FR_RADIUS_CODE_DISCONNECT_ACK
RFC3575/RFC5176 - Disconnect-Ack (positive)
Definition: defs.h:47
@ 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_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition: defs.h:34
@ FR_RADIUS_CODE_ACCOUNTING_RESPONSE
RFC2866 - Accounting-Response.
Definition: defs.h:37
@ FR_RADIUS_CODE_COA_NAK
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
Definition: defs.h:51
@ FR_RADIUS_CODE_COA_ACK
RFC3575/RFC5176 - CoA-Ack (positive)
Definition: defs.h:50
@ FR_RADIUS_CODE_DISCONNECT_NAK
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
Definition: defs.h:48
@ FR_RADIUS_CODE_PROTOCOL_ERROR
RFC7930 - Protocol-Error (generic NAK)
Definition: defs.h:52
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
Definition: defs.h:36
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition: defs.h:35
fr_value_box_t const ** out
Enumeration value.
Definition: dict.h:256
fr_dict_enum_value_t * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict_util.c:3349
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
char const * name
Enum name.
Definition: dict.h:227
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
Specifies a value which must be present for the module to function.
Definition: dict.h:255
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
static xlat_action_t xlat_func_radius_secret_verify(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Validates a request against a know shared secret.
Definition: base.c:839
uint32_t fr_hash_string(char const *p)
Definition: hash.c:865
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition: interpret.c:1403
fr_dict_attr_t const * attr_packet_type
Definition: base.c:91
fr_dict_attr_t const * attr_state
Definition: base.c:101
fr_dict_t const * dict_freeradius
Definition: base.c:77
fr_dict_t const * dict_radius
Definition: base.c:78
fr_dict_attr_t const * attr_user_name
Definition: base.c:102
void log_request_proto_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a list of protocol fr_pair_ts.
Definition: log.c:854
void log_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt,...)
Marshal variadic log arguments into a va_list and pass to normal logging functions.
Definition: log.c:612
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition: log.c:830
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define RPDEBUG2(fmt,...)
Definition: log.h:347
#define RWDEBUG(fmt,...)
Definition: log.h:361
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition: log.h:70
@ L_DBG
Only displayed when debugging is enabled.
Definition: log.h:59
main_config_t const * main_config
Main server configuration.
Definition: main_config.c:69
bool spawn_workers
Should the server spawn threads.
Definition: main_config.h:58
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
unlang_mod_actions_t const mod_actions_preacct
Definition: mod_action.c:59
unlang_mod_actions_t const mod_actions_authenticate
Definition: mod_action.c:29
unlang_mod_actions_t const mod_actions_accounting
Definition: mod_action.c:74
unlang_mod_actions_t const mod_actions_authorize
Definition: mod_action.c:44
unlang_mod_actions_t const mod_actions_postauth
Definition: mod_action.c:88
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
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 instantiation calls.
Definition: module_ctx.h:50
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
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:283
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
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1345
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition: pair.c:1689
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition: pair.c:770
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
Definition: print.c:39
RESUME(check_yiaddr)
Definition: base.c:133
RECV(for_any_server)
Validate a solicit/rebind/confirm message.
Definition: base.c:401
process_radius_auth_t auth
Authentication configuration.
Definition: base.c:149
static int mod_load(void)
Definition: base.c:901
CONF_SECTION * access_challenge
Definition: base.c:111
static fr_dict_attr_t const * attr_user_password
Definition: base.c:65
static fr_dict_attr_t const * attr_module_failure_message
Definition: base.c:56
static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: base.c:792
CONF_SECTION * coa_nak
Definition: base.c:120
static virtual_server_compile_t const compile_list[]
Definition: base.c:1136
static xlat_arg_parser_t const xlat_func_radius_secret_verify_args[]
Definition: base.c:822
CONF_SECTION * disconnect_ack
Definition: base.c:123
CONF_SECTION * protocol_error
Definition: base.c:127
CONF_SECTION * new_client
Definition: base.c:129
static fr_dict_attr_t const * attr_stripped_user_name
Definition: base.c:58
fr_dict_attr_autoload_t process_radius_dict_attr[]
Definition: base.c:71
fr_value_box_list_head_t proxy_state
These need to be copied into the response in exactly the same order as they were added.
Definition: base.c:155
static const conf_parser_t session_config[]
Definition: base.c:169
CONF_SECTION * coa_request
Definition: base.c:118
uint8_t state_server_id
Sets a specific byte in the state to allow the authenticating server to be identified in packet captu...
Definition: base.c:138
fr_dict_enum_autoload_t process_radius_dict_enum[]
Definition: base.c:96
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: base.c:892
fr_process_module_t process_radius
Definition: base.c:1229
static fr_dict_attr_t const * attr_auth_type
Definition: base.c:55
#define FR_RADIUS_PROCESS_CODE_VALID(_x)
Definition: base.c:159
static void radius_request_pairs_to_reply(request_t *request, process_radius_request_pairs_t *rctx)
Definition: base.c:265
CONF_SECTION * disconnect_nak
Definition: base.c:124
CONF_SECTION * access_accept
Definition: base.c:109
static fr_value_box_t const * enum_auth_type_reject
Definition: base.c:93
static fr_dict_attr_t const * attr_error_cause
Definition: base.c:67
static void mod_unload(void)
Definition: base.c:913
CONF_SECTION * add_client
Definition: base.c:130
static const conf_parser_t auth_config[]
Definition: base.c:177
fr_time_delta_t session_timeout
Maximum time between the last response and next request.
Definition: base.c:135
CONF_SECTION * server_cs
Our virtual server.
Definition: base.c:146
static fr_process_state_t const process_state[]
Definition: base.c:923
CONF_SECTION * access_request
Definition: base.c:108
static fr_dict_attr_t const * attr_proxy_state
Definition: base.c:62
static void radius_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition: base.c:193
static fr_value_box_t const * enum_auth_type_accept
Definition: base.c:92
uint32_t max_session
Maximum ongoing session allowed.
Definition: base.c:136
CONF_SECTION * status_server
Definition: base.c:116
CONF_SECTION * access_reject
Definition: base.c:110
static fr_dict_attr_t const * attr_acct_status_type
Definition: base.c:60
CONF_SECTION * disconnect_request
Definition: base.c:122
CONF_SECTION * accounting_request
Definition: base.c:113
CONF_SECTION * coa_ack
Definition: base.c:119
CONF_SECTION * do_not_respond
Definition: base.c:126
process_radius_sections_t sections
Pointers to various config sections we need to execute.
Definition: base.c:147
static process_radius_request_pairs_t * radius_request_pairs_store(request_t *request)
Keep a copy of some attributes to keep them from being tamptered with.
Definition: base.c:236
static fr_dict_attr_t const * attr_original_packet_code
Definition: base.c:66
static const conf_parser_t config[]
Definition: base.c:183
fr_dict_autoload_t process_radius_dict[]
Definition: base.c:49
fr_state_tree_t * state_tree
State tree to link multiple requests/responses.
Definition: base.c:142
static fr_dict_attr_t const * attr_event_timestamp
Definition: base.c:68
CONF_SECTION * accounting_response
Definition: base.c:114
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: base.c:879
static fr_dict_attr_t const * attr_module_success_message
Definition: base.c:57
CONF_SECTION * deny_client
Definition: base.c:131
Records fields from the original request so we have a known good copy.
Definition: base.c:154
#define PROCESS_TRACE
Trace each state function as it's entered.
Definition: process.h:65
module_t common
Common fields for all loadable modules.
Definition: process.h:55
Common public symbol definition for all process modules.
Definition: process.h:54
int fr_radius_verify(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len, bool require_message_authenticator, bool limit_proxy_state)
Verify a request / response packet.
Definition: base.c:777
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition: base.c:112
static char * secret
Definition: radclient-ng.c:69
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG_ENABLED2()
Definition: radclient.h:50
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define RDEBUG(fmt,...)
Definition: radclient.h:53
#define RDEBUG_ENABLED()
Definition: radclient.h:49
static void send_reply(int sockfd, fr_channel_data_t *reply)
Definition: radius1_test.c:190
#define FR_RADIUS_PACKET_CODE_VALID(_x)
Definition: radius.h:52
void fr_rand_buffer(void *start, size_t length)
Definition: rand.c:126
fr_table_num_sorted_t const rcode_table[]
Definition: rcode.c:35
#define RETURN_MODULE_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition: rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition: rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition: rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition: rcode.h:49
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition: rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition: rcode.h:50
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition: rcode.h:44
#define request_is_dynamic_client(_x)
Definition: request.h:162
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
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition: pair.h:129
fr_state_tree_t * fr_state_tree_init(TALLOC_CTX *ctx, fr_dict_attr_t const *da, bool thread_safe, uint32_t max_sessions, fr_time_delta_t timeout, uint8_t server_id, uint32_t context_id)
Initialise a new state tree.
Definition: state.c:222
void fr_state_discard(fr_state_tree_t *state, request_t *request)
Called when sending an Access-Accept/Access-Reject to discard state information.
Definition: state.c:606
int fr_request_to_state(fr_state_tree_t *state, request_t *request)
Transfer ownership of the state fr_pair_ts and ctx, back to a state entry.
Definition: state.c:737
int fr_state_to_request(fr_state_tree_t *state, request_t *request)
Copy a pointer to the head of the list of state fr_pair_ts (and their ctx) into the request.
Definition: state.c:660
unlang_action_t unlang_module_yield_to_section(rlm_rcode_t *p_result, request_t *request, CONF_SECTION *subcs, rlm_rcode_t default_rcode, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Definition: module.c:248
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
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:772
#define talloc_get_type_abort_const
Definition: talloc.h:282
static fr_unix_time_t fr_unix_time_sub_time_delta(fr_unix_time_t a, fr_time_delta_t b)
Definition: time.h:341
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:590
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
Definition: time.h:688
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition: xlat.h:365
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
unsigned int code
Packet code (type).
Definition: packet.h:61
fr_socket_t socket
This packet was received on.
Definition: packet.h:57
int id
Packet ID (used to link requests/responses).
Definition: packet.h:60
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition: socket.h:78
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition: value.c:676
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3740
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:621
#define fr_box_ipaddr(_val)
Definition: value.h:294
static fr_value_box_t * fr_value_box_acopy(TALLOC_CTX *ctx, fr_value_box_t const *src)
Copy an existing box, allocating a new box to hold its contents.
Definition: value.h:711
#define fr_value_box_list_foreach(_list_head, _iter)
Definition: value.h:206
static size_t char ** out
Definition: value.h:997
int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const *subcs_name, fr_dict_attr_t const *da)
Define a values for Auth-Type attributes by the sections present in a virtual-server.
#define COMPILE_TERMINATOR
section_name_t const * section
Identifier for the section.
Processing sections which are allowed in this virtual server.
An xlat calling ctx.
Definition: xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:365
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:218
void xlat_func_unregister(char const *name)
Unregister an xlat function.
Definition: xlat_func.c:519