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: 2dbae6f936d318297558cf7464749d225cde46ca $
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 
67 static fr_dict_attr_t const *attr_state;
72 
75  { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
76  { .out = &attr_module_failure_message, .name = "Module-Failure-Message", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
77  { .out = &attr_module_success_message, .name = "Module-Success-Message", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
78  { .out = &attr_stripped_user_name, .name = "Stripped-User-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
79 
80  { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
81  { .out = &attr_calling_station_id, .name = "Calling-Station-Id", .type = FR_TYPE_STRING, .dict = &dict_radius },
82  { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
83  { .out = &attr_nas_port, .name = "NAS-Port", .type = FR_TYPE_UINT32, .dict = &dict_radius },
84  { .out = &attr_proxy_state, .name = "Proxy-State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
85  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
86  { .out = &attr_service_type, .name = "Service-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
87  { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
88  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
89  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
90 
91  { .out = &attr_original_packet_code, .name = "Extended-Attribute-1.Original-Packet-Code", .type = FR_TYPE_UINT32, .dict = &dict_radius },
92  { .out = &attr_error_cause, .name = "Error-Cause", .type = FR_TYPE_UINT32, .dict = &dict_radius },
93 
94  { NULL }
95 };
96 
99 
102  { .out = &enum_auth_type_accept, .name = "Accept", .attr = &attr_auth_type },
103  { .out = &enum_auth_type_reject, .name = "Reject", .attr = &attr_auth_type },
104  { NULL }
105 };
106 
107 /*
108  * RADIUS state machine configuration
109  */
110 typedef struct {
111  uint64_t nothing; // so that "access_request" isn't at offset 0
112 
117 
120 
122 
126 
130 
132  CONF_SECTION *protocol_error; /* @todo - allow protocol error as a reject reply? */
133 
138 
139 typedef struct {
140  fr_time_delta_t session_timeout; //!< Maximum time between the last response and next request.
141  uint32_t max_session; //!< Maximum ongoing session allowed.
142 
143  uint8_t state_server_id; //!< Sets a specific byte in the state to allow the
144  //!< authenticating server to be identified in packet
145  //!<captures.
146 
147  fr_state_tree_t *state_tree; //!< State tree to link multiple requests/responses.
149 
150 typedef struct {
151  CONF_SECTION *server_cs; //!< Our virtual server.
152  process_radius_sections_t sections; //!< Pointers to various config sections
153  ///< we need to execute.
154  process_radius_auth_t auth; //!< Authentication configuration.
156 
157 /** Records fields from the original request so we have a known good copy
158  */
159 typedef struct {
160  fr_value_box_list_head_t proxy_state; //!< These need to be copied into the response in exactly
161  ///< the same order as they were added.
163 
164 #define FR_RADIUS_PROCESS_CODE_VALID(_x) (FR_RADIUS_PACKET_CODE_VALID(_x) || (_x == FR_RADIUS_CODE_DO_NOT_RESPOND))
165 
166 #define PROCESS_PACKET_TYPE fr_radius_packet_code_t
167 #define PROCESS_CODE_MAX FR_RADIUS_CODE_MAX
168 #define PROCESS_CODE_DO_NOT_RESPOND FR_RADIUS_CODE_DO_NOT_RESPOND
169 #define PROCESS_PACKET_CODE_VALID FR_RADIUS_PROCESS_CODE_VALID
170 #define PROCESS_INST process_radius_t
171 #define PROCESS_CODE_DYNAMIC_CLIENT FR_RADIUS_CODE_ACCESS_ACCEPT
172 #include <freeradius-devel/server/process.h>
173 
174 static const conf_parser_t session_config[] = {
175  { FR_CONF_OFFSET("timeout", process_radius_auth_t, session_timeout), .dflt = "15" },
176  { FR_CONF_OFFSET("max", process_radius_auth_t, max_session), .dflt = "4096" },
177  { FR_CONF_OFFSET("state_server_id", process_radius_auth_t, state_server_id) },
178 
180 };
181 
182 static const conf_parser_t auth_config[] = {
183  { FR_CONF_POINTER("session", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) session_config },
184 
186 };
187 
188 static const conf_parser_t config[] = {
189  { FR_CONF_POINTER("Access-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) auth_config,
190  .offset = offsetof(process_radius_t, auth), },
191 
193 };
194 
195 /*
196  * Debug the packet if requested.
197  */
198 static void radius_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
199 {
200 #ifdef WITH_IFINDEX_NAME_RESOLUTION
201  char if_name[IFNAMSIZ];
202 #endif
203 
204  if (!packet) return;
205  if (!RDEBUG_ENABLED) return;
206 
207  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 "
208 #ifdef WITH_IFINDEX_NAME_RESOLUTION
209  "%s%s%s"
210 #endif
211  "",
212  received ? "Received" : "Sending",
213  fr_radius_packet_name[packet->code],
214  packet->id,
215  packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "",
216  fr_box_ipaddr(packet->socket.inet.src_ipaddr),
217  packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "",
218  packet->socket.inet.src_port,
219  packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "",
220  fr_box_ipaddr(packet->socket.inet.dst_ipaddr),
221  packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "",
222  packet->socket.inet.dst_port
223 #ifdef WITH_IFINDEX_NAME_RESOLUTION
224  , packet->socket.inet.ifindex ? "via " : "",
225  packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "",
226  packet->socket.inet.ifindex ? " " : ""
227 #endif
228  );
229 
230  if (received || request->parent) {
231  log_request_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
232  } else {
233  log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
234  }
235 }
236 
237 /** Keep a copy of some attributes to keep them from being tamptered with
238  *
239  */
240 static inline CC_HINT(always_inline)
242 {
243  fr_pair_t *proxy_state;
245 
246  /*
247  * Don't bother allocing the struct if there's no proxy state to store
248  */
249  proxy_state = fr_pair_find_by_da(&request->request_pairs, NULL, attr_proxy_state);
250  if (!proxy_state) return 0;
251 
253  fr_value_box_list_init(&rctx->proxy_state);
254 
255  /*
256  * We don't use fr_pair_list_copy_by_da, to avoid doing the lookup for
257  * the first proxy-state attr again.
258  */
259  do {
260  fr_value_box_t *proxy_state_value;
261 
262  MEM((proxy_state_value = fr_value_box_acopy(rctx, &proxy_state->data)));
263  fr_value_box_list_insert_tail(&rctx->proxy_state, proxy_state_value);
264  } while ((proxy_state = fr_pair_find_by_da(&request->request_pairs, proxy_state, attr_proxy_state)));
265 
266  return rctx;
267 }
268 
269 static inline CC_HINT(always_inline)
271 {
272  if (!rctx) return;
273 
274  /*
275  * Proxy-State is a link-level signal between RADIUS
276  * client and server. RFC 2865 Section 5.33 says that
277  * Proxy-State is an opaque field, and implementations
278  * most not examine it, interpret it, or assign it any
279  * meaning. Implementations must also copy all Proxy-State
280  * from the request to the reply.
281  *
282  * The rlm_radius module already deletes any Proxy-State
283  * from the reply before appending the proxy reply to the
284  * current reply.
285  *
286  * If any policy creates Proxy-State, that could affect
287  * individual RADIUS links (perhaps), and that would be
288  * wrong. As such, we nuke any nonsensical Proxy-State
289  * added by policies or errant modules, and instead just
290  * do exactly what the RFCs require us to do. No more.
291  */
292  fr_pair_delete_by_da(&request->reply_pairs, attr_proxy_state);
293 
294  RDEBUG3("Adding Proxy-State attributes from request");
295  RINDENT();
296  fr_value_box_list_foreach(&rctx->proxy_state, proxy_state_value) {
297  fr_pair_t *vp;
298 
299  MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_proxy_state));
300  fr_value_box_copy(vp, &vp->data, proxy_state_value);
301  fr_pair_append(&request->reply_pairs, vp);
302  RDEBUG3("&reply.%pP", vp);
303  }
304  REXDENT();
305 }
306 
307 /** A wrapper around recv generic which stores fields from the request
308  */
309 RECV(generic_radius_request)
310 {
311  module_ctx_t our_mctx = *mctx;
312 
313  fr_assert_msg(!mctx->rctx, "rctx not expected here");
314  our_mctx.rctx = radius_request_pairs_store(request);
315  mctx = &our_mctx; /* Our mutable mctx */
316 
317  return CALL_RECV(generic);
318 }
319 
320 /** A wrapper around send generic which restores fields
321  *
322  */
323 RESUME(generic_radius_response)
324 {
325  if (mctx->rctx) radius_request_pairs_to_reply(request, talloc_get_type_abort(mctx->rctx, process_radius_request_pairs_t));
326 
327  return CALL_RESUME(send_generic);
328 }
329 
330 RECV(access_request)
331 {
333 
334  /*
335  * Only reject if the state has already been thawed.
336  * It could be that the state value wasn't intended
337  * for us, and we're just proxying upstream.
338  */
339  if (fr_state_to_request(inst->auth.state_tree, request) < 0) {
340  return CALL_SEND_TYPE(FR_RADIUS_CODE_ACCESS_REJECT);
341  }
342 
343  return CALL_RECV(generic_radius_request);
344 }
345 
346 RESUME(auth_type);
347 
348 RESUME(access_request)
349 {
350  rlm_rcode_t rcode = *p_result;
351  fr_pair_t *vp;
352  CONF_SECTION *cs;
353  fr_dict_enum_value_t const *dv;
354  fr_process_state_t const *state;
356 
358 
360 
361  /*
362  * See if the return code from "recv Access-Request" says we reject, or continue.
363  */
364  UPDATE_STATE(packet);
365 
366  request->reply->code = state->packet_type[rcode];
367  if (!request->reply->code) request->reply->code = state->default_reply;
368 
369  /*
370  * Something set reject, we're done.
371  */
372  if (request->reply->code == FR_RADIUS_CODE_ACCESS_REJECT) {
373  RDEBUG("The 'recv Access-Request' section returned %s - rejecting the request",
374  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
375 
376  send_reply:
377  UPDATE_STATE(reply);
378 
379  fr_assert(state->send != NULL);
380  return CALL_SEND_STATE(state);
381  }
382 
383  if (request->reply->code) {
384  goto send_reply;
385  }
386 
387  /*
388  * A policy _or_ a module can hard-code the reply.
389  */
390  if (!request->reply->code) {
391  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_packet_type);
392  if (vp && FR_RADIUS_PROCESS_CODE_VALID(vp->vp_uint32)) {
393  request->reply->code = vp->vp_uint32;
394  goto send_reply;
395  }
396  }
397 
398  /*
399  * Run authenticate foo { ... }
400  *
401  * If we can't find Auth-Type, OR if we can't find
402  * Auth-Type = foo, then it's a reject.
403  */
404  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_auth_type);
405  if (!vp) {
406  RDEBUG("No 'Auth-Type' attribute found, cannot authenticate the user - rejecting the request");
407 
408  reject:
409  request->reply->code = FR_RADIUS_CODE_ACCESS_REJECT;
410  goto send_reply;
411  }
412 
413  dv = fr_dict_enum_by_value(vp->da, &vp->data);
414  if (!dv) {
415  RDEBUG("Invalid value for 'Auth-Type' attribute, cannot authenticate the user - rejecting the request");
416 
417  goto reject;
418  }
419 
420  /*
421  * The magic Auth-Type Accept value
422  * which means skip the authenticate
423  * section.
424  *
425  * And Reject means always reject. Tho the admin should
426  * just return "reject" from the section.
427  */
429  request->reply->code = FR_RADIUS_CODE_ACCESS_ACCEPT;
430  goto send_reply;
431 
432  } else if (fr_value_box_cmp(enum_auth_type_reject, dv->value) == 0) {
433  request->reply->code = FR_RADIUS_CODE_ACCESS_REJECT;
434  goto send_reply;
435  }
436 
437  cs = cf_section_find(inst->server_cs, "authenticate", dv->name);
438  if (!cs) {
439  RDEBUG2("No 'authenticate %s { ... }' section found - rejecting the request", dv->name);
440  goto reject;
441  }
442 
443  /*
444  * Run the "Authenticate = foo" section.
445  *
446  * And continue with sending the generic reply.
447  */
448  RDEBUG("Running 'authenticate %s' from file %s", cf_section_name2(cs), cf_filename(cs));
449  return unlang_module_yield_to_section(p_result, request,
450  cs, RLM_MODULE_NOOP, resume_auth_type,
451  NULL, 0, mctx->rctx);
452 }
453 
454 RESUME(auth_type)
455 {
456  static const fr_process_rcode_t auth_type_rcode = {
465  };
466 
467  rlm_rcode_t rcode = *p_result;
468  fr_pair_t *vp;
469  fr_process_state_t const *state;
470 
472 
474 
475  if (auth_type_rcode[rcode] == FR_RADIUS_CODE_DO_NOT_RESPOND) {
476  request->reply->code = auth_type_rcode[rcode];
477  UPDATE_STATE(reply);
478 
479  RDEBUG("The 'authenticate' section returned %s - not sending a response",
480  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
481 
482  fr_assert(state->send != NULL);
483  return state->send(p_result, mctx, request);
484  }
485 
486  /*
487  * Most cases except handled...
488  */
489  if (auth_type_rcode[rcode]) request->reply->code = auth_type_rcode[rcode];
490 
491  switch (request->reply->code) {
492  case 0:
493  RDEBUG("No reply code was set. Forcing to Access-Reject");
494  request->reply->code = FR_RADIUS_CODE_ACCESS_REJECT;
495  FALL_THROUGH;
496 
497  /*
498  * Print complaints before running "send Access-Reject"
499  */
501  RDEBUG2("Failed to authenticate the user");
502 
503  /*
504  * Maybe the shared secret is wrong?
505  */
506  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
507  if (vp) {
508  if (RDEBUG_ENABLED2) {
509  uint8_t const *p;
510 
511  p = (uint8_t const *) vp->vp_strvalue;
512  while (*p) {
513  int size;
514 
515  size = fr_utf8_char(p, -1);
516  if (!size) {
517  RWDEBUG("Unprintable characters in the password. "
518  "Double-check the shared secret on the server "
519  "and the NAS!");
520  break;
521  }
522  p += size;
523  }
524  }
525  }
526  break;
527 
528  /*
529  * Access-Challenge sections require a State. If there is
530  * none, create one here. This is so that the State
531  * attribute is accessible in the "send Access-Challenge"
532  * section.
533  */
535  if ((vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_state)) != NULL) {
536  uint8_t buffer[16];
537 
538  fr_rand_buffer(buffer, sizeof(buffer));
539 
541  fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
542  }
543  break;
544 
545  default:
546  break;
547 
548  }
549  UPDATE_STATE(reply);
550 
551  fr_assert(state->send != NULL);
552  return state->send(p_result, mctx, request);
553 }
554 
555 RESUME(access_accept)
556 {
557  fr_pair_t *vp;
559 
561 
562  /*
563  * Check that there is a name which can be used to
564  * identify the user. The configuration depends on
565  * User-Name or Stripped-User-Name existing, and being
566  * (mostly) unique to that user.
567  */
568  if (!request->parent &&
569  ((vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name)) != NULL) &&
570  (vp->vp_strvalue[0] == '@') &&
571  !fr_pair_find_by_da(&request->request_pairs, NULL, attr_stripped_user_name)) {
572  RWDEBUG("User-Name is anonymized, and no Stripped-User-Name exists.");
573  RWDEBUG("It may be difficult or impossible to identify the user.");
574  RWDEBUG("Please update Stripped-User-Name with information which identifies the user.");
575  }
576 
577  fr_state_discard(inst->auth.state_tree, request);
578  radius_request_pairs_to_reply(request, mctx->rctx);
580 }
581 
582 RESUME(access_reject)
583 {
585 
587 
588  fr_state_discard(inst->auth.state_tree, request);
589  radius_request_pairs_to_reply(request, mctx->rctx);
591 }
592 
593 RESUME(access_challenge)
594 {
596 
598 
599  /*
600  * Cache the state context.
601  *
602  * If this fails, don't respond to the request.
603  */
604  if (fr_request_to_state(inst->auth.state_tree, request) < 0) {
605  return CALL_SEND_TYPE(FR_RADIUS_CODE_DO_NOT_RESPOND);
606  }
607 
608  fr_assert(request->reply->code == FR_RADIUS_CODE_ACCESS_CHALLENGE);
609  radius_request_pairs_to_reply(request, mctx->rctx);
611 }
612 
613 RESUME(acct_type)
614 {
615  static const fr_process_rcode_t acct_type_rcode = {
621  };
622 
623  rlm_rcode_t rcode = *p_result;
624  fr_process_state_t const *state;
625 
627 
629  fr_assert(FR_RADIUS_PROCESS_CODE_VALID(request->reply->code));
630 
631  if (acct_type_rcode[rcode]) {
632  fr_assert(acct_type_rcode[rcode] == FR_RADIUS_CODE_DO_NOT_RESPOND);
633 
634  request->reply->code = acct_type_rcode[rcode];
635  UPDATE_STATE(reply);
636 
637  RDEBUG("The 'accounting' section returned %s - not sending a response",
638  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
639 
640  fr_assert(state->send != NULL);
641  return state->send(p_result, mctx, request);
642  }
643 
644  request->reply->code = FR_RADIUS_CODE_ACCOUNTING_RESPONSE;
645  UPDATE_STATE(reply);
646 
647  fr_assert(state->send != NULL);
648  return state->send(p_result, mctx, request);
649 }
650 
651 RESUME(accounting_request)
652 {
653  rlm_rcode_t rcode = *p_result;
654  fr_pair_t *vp;
655  CONF_SECTION *cs;
656  fr_dict_enum_value_t const *dv;
657  fr_process_state_t const *state;
659 
661 
663 
664  UPDATE_STATE(packet);
665  fr_assert(state->packet_type[rcode] != 0);
666 
667  request->reply->code = state->packet_type[rcode];
668  UPDATE_STATE_CS(reply);
669 
670  if (request->reply->code == FR_RADIUS_CODE_DO_NOT_RESPOND) {
671  RDEBUG("The 'recv Accounting-Request' section returned %s - not sending a response",
672  fr_table_str_by_value(rcode_table, rcode, "<INVALID>"));
673 
674  send_reply:
675  fr_assert(state->send != NULL);
676  return CALL_SEND_STATE(state);
677  }
678 
679  /*
680  * Run accounting foo { ... }
681  */
682  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_acct_status_type);
683  if (!vp) goto send_reply;
684 
685  dv = fr_dict_enum_by_value(vp->da, &vp->data);
686  if (!dv) goto send_reply;
687 
688  cs = cf_section_find(inst->server_cs, "accounting", dv->name);
689  if (!cs) {
690  RDEBUG2("No 'accounting %s { ... }' section found - skipping...", dv->name);
691  goto send_reply;
692  }
693 
694  /*
695  * Run the "Acct-Status-Type = foo" section.
696  *
697  * And continue with sending the generic reply.
698  */
699  return unlang_module_yield_to_section(p_result, request,
700  cs, RLM_MODULE_NOOP, resume_acct_type,
701  NULL, 0, mctx->rctx);
702 }
703 
704 #if 0
705 // @todo - send canned responses like in v3?
706 RECV(status_server)
707 {
709 }
710 
711 RESUME(status_server)
712 {
714 }
715 #endif
716 
717 RESUME(protocol_error)
718 {
719  fr_pair_t *vp;
720 
722 
723  fr_assert(FR_RADIUS_PACKET_CODE_VALID(request->reply->code));
724 
725  /*
726  * https://tools.ietf.org/html/rfc7930#section-4
727  */
728  vp = fr_pair_find_by_da_nested(&request->reply_pairs, NULL, attr_original_packet_code);
729  if (!vp) {
730  vp = fr_pair_afrom_da(request->reply_ctx, attr_original_packet_code);
731  if (vp) {
732  vp->vp_uint32 = request->packet->code;
733  fr_pair_append(&request->reply_pairs, vp);
734  }
735  }
736 
737  /*
738  * If there's no Error-Cause, then include a generic 404.
739  */
740  vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_error_cause);
741  if (!vp) {
742  vp = fr_pair_afrom_da(request->reply_ctx, attr_error_cause);
743  if (vp) {
744  vp->vp_uint32 = FR_ERROR_CAUSE_VALUE_INVALID_REQUEST;
745  fr_pair_append(&request->reply_pairs, vp);
746  }
747  }
748 
749  /*
750  * And do the generic processing after running a "send" section.
751  */
752  return CALL_RESUME(send_generic);
753 }
754 
755 static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
756 {
757  fr_process_state_t const *state;
758 
760 
762 
763  request->component = "radius";
764  request->module = NULL;
765  fr_assert(request->dict == dict_radius);
766 
767  fr_assert(FR_RADIUS_PACKET_CODE_VALID(request->packet->code));
768 
769  UPDATE_STATE(packet);
770 
771  if (!state->recv) {
772  REDEBUG("Invalid packet type (%u)", request->packet->code);
774  }
775 
776  radius_packet_debug(request, request->packet, &request->request_pairs, true);
777 
778  if (unlikely(request_is_dynamic_client(request))) {
779  return new_client(p_result, mctx, request);
780  }
781 
782  return state->recv(p_result, mctx, request);
783 }
784 
786  { .required = true, .single = true, .type = FR_TYPE_OCTETS },
788 };
789 
790 /** Validates a request against a know shared secret
791  *
792  * Designed for the specific purpose of verifying dynamic clients
793  * against a know shared secret.
794  *
795  * Example:
796 @verbatim
797 %radius_secret_verify(<secret>)
798 @endverbatim
799  *
800  * @ingroup xlat_functions
801  */
803  request_t *request, fr_value_box_list_t *args)
804 {
805  fr_value_box_t *secret, *vb;
806  int ret;
807  bool require_ma = false;
808 
809  XLAT_ARGS(args, &secret);
810 
811  if (request->dict != dict_radius) return XLAT_ACTION_FAIL;
812 
813  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
814 
815  /*
816  * Only Access-Requests require a Message-Authenticator.
817  * All the other packet types are signed using the
818  * authenticator field.
819  */
820  if (request->packet->code == FR_RADIUS_CODE_ACCESS_REQUEST) require_ma = true;
821 
822  ret = fr_radius_verify(request->packet->data, NULL, secret->vb_octets, secret->vb_length, require_ma);
823  switch (ret) {
824  case 0:
825  vb->vb_bool = true;
826  break;
827 
828  case -1:
829  RPEDEBUG("Failed verifying secret");
830  return XLAT_ACTION_FAIL;
831 
832  case -2:
833  RPDEBUG2("Provided secret was not used to sign this packet");
834  vb->vb_bool = false;
835  break;
836  }
837  fr_dcursor_append(out, vb);
838 
839  return XLAT_ACTION_DONE;
840 }
841 
842 static int mod_instantiate(module_inst_ctx_t const *mctx)
843 {
844  process_radius_t *inst = talloc_get_type_abort(mctx->inst->data, process_radius_t);
845 
846  inst->auth.state_tree = fr_state_tree_init(inst, attr_state, main_config->spawn_workers, inst->auth.max_session,
847  inst->auth.session_timeout, inst->auth.state_server_id,
848  fr_hash_string(cf_section_name2(inst->server_cs)));
849 
850  return 0;
851 }
852 
853 static int mod_bootstrap(module_inst_ctx_t const *mctx)
854 {
855  process_radius_t *inst = talloc_get_type_abort(mctx->inst->data, process_radius_t);
856 
857  inst->server_cs = cf_item_to_section(cf_parent(mctx->inst->conf));
858  if (virtual_server_section_attribute_define(inst->server_cs, "authenticate", attr_auth_type) < 0) return -1;
859 
860  return 0;
861 }
862 
863 static int mod_load(void)
864 {
865  xlat_t *xlat;
866 
867  if (unlikely(!(xlat = xlat_func_register(NULL, "radius.secret.verify", xlat_func_radius_secret_verify,
868  FR_TYPE_BOOL)))) return -1;
869 
871 
872  return 0;
873 }
874 
875 /*
876  * rcodes not listed under a packet_type
877  * mean that the packet code will not be
878  * changed.
879  */
880 static fr_process_state_t const process_state[] = {
882  .packet_type = {
888  },
889  .rcode = RLM_MODULE_NOOP,
890  .recv = recv_access_request,
891  .resume = resume_access_request,
892  .section_offset = offsetof(process_radius_sections_t, access_request),
893  },
895  .packet_type = {
900  },
901  .rcode = RLM_MODULE_NOOP,
902  .send = send_generic,
903  .resume = resume_access_accept,
904  .section_offset = offsetof(process_radius_sections_t, access_accept),
905  },
907  .packet_type = {
912  },
913  .rcode = RLM_MODULE_NOOP,
914  .send = send_generic,
915  .resume = resume_access_reject,
916  .section_offset = offsetof(process_radius_sections_t, access_reject),
917  },
919  .packet_type = {
924  },
925  .rcode = RLM_MODULE_NOOP,
926  .send = send_generic,
927  .resume = resume_access_challenge,
928  .section_offset = offsetof(process_radius_sections_t, access_challenge),
929  },
930 
932  .packet_type = {
937 
943  },
944  .rcode = RLM_MODULE_NOOP,
945  .recv = recv_generic_radius_request,
946  .resume = resume_accounting_request,
947  .section_offset = offsetof(process_radius_sections_t, accounting_request),
948  },
950  .packet_type = {
956  },
957  .rcode = RLM_MODULE_NOOP,
958  .send = send_generic,
959  .resume = resume_generic_radius_response,
960  .section_offset = offsetof(process_radius_sections_t, accounting_response),
961  },
962  [ FR_RADIUS_CODE_STATUS_SERVER ] = { /* @todo - negotiation, stats, etc. */
963  .packet_type = {
966 
973  },
974  .rcode = RLM_MODULE_NOOP,
975  .recv = recv_generic,
976  .resume = resume_recv_generic,
977  .section_offset = offsetof(process_radius_sections_t, status_server),
978  },
980  .packet_type = {
985 
990  },
991  .rcode = RLM_MODULE_NOOP,
992  .recv = recv_generic_radius_request,
993  .resume = resume_recv_generic,
994  .section_offset = offsetof(process_radius_sections_t, coa_request),
995  },
996  [ FR_RADIUS_CODE_COA_ACK ] = {
997  .packet_type = {
1002  },
1003  .rcode = RLM_MODULE_NOOP,
1004  .send = send_generic,
1005  .resume = resume_generic_radius_response,
1006  .section_offset = offsetof(process_radius_sections_t, coa_ack),
1007  },
1008  [ FR_RADIUS_CODE_COA_NAK ] = {
1009  .packet_type = {
1014  },
1015  .rcode = RLM_MODULE_NOOP,
1016  .send = send_generic,
1017  .resume = resume_generic_radius_response,
1018  .section_offset = offsetof(process_radius_sections_t, coa_nak),
1019  },
1021  .packet_type = {
1026 
1031  },
1032  .rcode = RLM_MODULE_NOOP,
1033  .recv = recv_generic,
1034  .resume = resume_recv_generic,
1035  .section_offset = offsetof(process_radius_sections_t, disconnect_request),
1036  },
1038  .packet_type = {
1043  },
1044  .rcode = RLM_MODULE_NOOP,
1045  .send = send_generic,
1046  .resume = resume_generic_radius_response,
1047  .section_offset = offsetof(process_radius_sections_t, disconnect_ack),
1048  },
1050  .packet_type = {
1055  },
1056  .rcode = RLM_MODULE_NOOP,
1057  .send = send_generic,
1058  .resume = resume_generic_radius_response,
1059  .section_offset = offsetof(process_radius_sections_t, disconnect_nak),
1060  },
1061  [ FR_RADIUS_CODE_PROTOCOL_ERROR ] = { /* @todo - fill out required fields */
1062  .packet_type = {
1067  },
1068  .rcode = RLM_MODULE_NOOP,
1069  .send = send_generic,
1070  .resume = resume_protocol_error,
1071  .section_offset = offsetof(process_radius_sections_t, protocol_error),
1072  },
1074  .packet_type = {
1079 
1085  },
1086  .rcode = RLM_MODULE_NOOP,
1087  .send = send_generic,
1088  .resume = resume_send_generic,
1089  .section_offset = offsetof(process_radius_sections_t, do_not_respond),
1090  }
1091 };
1092 
1094  {
1095  .name = "recv",
1096  .name2 = "Access-Request",
1097  .component = MOD_AUTHORIZE,
1098  .offset = PROCESS_CONF_OFFSET(access_request),
1099  },
1100  {
1101  .name = "send",
1102  .name2 = "Access-Accept",
1103  .component = MOD_POST_AUTH,
1104  .offset = PROCESS_CONF_OFFSET(access_accept),
1105  },
1106  {
1107  .name = "send",
1108  .name2 = "Access-Challenge",
1109  .component = MOD_POST_AUTH,
1110  .offset = PROCESS_CONF_OFFSET(access_challenge),
1111  },
1112  {
1113  .name = "send",
1114  .name2 = "Access-Reject",
1115  .component = MOD_POST_AUTH,
1116  .offset = PROCESS_CONF_OFFSET(access_reject),
1117  },
1118 
1119  {
1120  .name = "recv",
1121  .name2 = "Accounting-Request",
1122  .component = MOD_PREACCT,
1123  .offset = PROCESS_CONF_OFFSET(accounting_request),
1124  },
1125  {
1126  .name = "send",
1127  .name2 = "Accounting-Response",
1128  .component = MOD_ACCOUNTING,
1129  .offset = PROCESS_CONF_OFFSET(accounting_response),
1130  },
1131 
1132  {
1133  .name = "recv",
1134  .name2 = "Status-Server",
1135  .component = MOD_AUTHORIZE,
1136  .offset = PROCESS_CONF_OFFSET(status_server),
1137  },
1138  {
1139  .name = "recv",
1140  .name2 = "CoA-Request",
1141  .component = MOD_AUTHORIZE,
1142  .offset = PROCESS_CONF_OFFSET(coa_request),
1143  },
1144  {
1145  .name = "send",
1146  .name2 = "CoA-ACK",
1147  .component = MOD_POST_AUTH,
1148  .offset = PROCESS_CONF_OFFSET(coa_ack),
1149  },
1150  {
1151  .name = "send",.name2 = "CoA-NAK",
1152  .component = MOD_AUTHORIZE,
1153  .offset = PROCESS_CONF_OFFSET(coa_nak),
1154  },
1155  {
1156  .name = "recv",
1157  .name2 = "Disconnect-Request",
1158  .component = MOD_AUTHORIZE,
1159  .offset = PROCESS_CONF_OFFSET(disconnect_request),
1160  },
1161  {
1162  .name = "send",
1163  .name2 = "Disconnect-ACK",
1164  .component = MOD_POST_AUTH,
1165  .offset = PROCESS_CONF_OFFSET(disconnect_ack),
1166  },
1167  {
1168  .name = "send",
1169  .name2 = "Disconnect-NAK",
1170  .component = MOD_POST_AUTH,
1171  .offset = PROCESS_CONF_OFFSET(disconnect_nak),
1172  },
1173  {
1174  .name = "send",
1175  .name2 = "Protocol-Error",
1176  .component = MOD_POST_AUTH,
1177  .offset = PROCESS_CONF_OFFSET(protocol_error),
1178  },
1179  {
1180  .name = "send",
1181  .name2 = "Do-Not-Respond",
1182  .component = MOD_POST_AUTH,
1183  .offset = PROCESS_CONF_OFFSET(do_not_respond),
1184  },
1185  {
1186  .name = "authenticate",
1187  .name2 = CF_IDENT_ANY,
1188  .component = MOD_AUTHENTICATE
1189  },
1190  {
1191  .name = "accounting",
1192  .name2 = CF_IDENT_ANY,
1193  .component = MOD_AUTHENTICATE
1194  },
1195 
1196  DYNAMIC_CLIENT_SECTIONS,
1197 
1199 };
1200 
1203  .common = {
1204  .magic = MODULE_MAGIC_INIT,
1205  .name = "radius",
1206  .config = config,
1207  .inst_size = sizeof(process_radius_t),
1208 
1209  .onload = mod_load,
1210  .bootstrap = mod_bootstrap,
1212  },
1213  .process = mod_process,
1214  .compile_list = compile_list,
1215  .dict = &dict_radius,
1216 };
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:378
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_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:400
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:970
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:649
#define cf_parent(_cf)
Definition: cf_util.h:98
#define cf_filename(_cf)
Definition: cf_util.h:104
#define CF_IDENT_ANY
Definition: cf_util.h:78
@ MOD_POST_AUTH
7 methods index for postauth section.
Definition: components.h:37
@ MOD_AUTHORIZE
1 methods index for authorize section.
Definition: components.h:34
@ MOD_ACCOUNTING
3 methods index for accounting section.
Definition: components.h:36
@ MOD_PREACCT
2 methods index for preacct section.
Definition: components.h:35
@ MOD_AUTHENTICATE
0 methods index for authenticate section.
Definition: components.h:33
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
#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:208
@ 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:239
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:2946
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
fr_value_box_t const * value
Enum value (what name maps to).
Definition: dict.h:213
char const * name
Enum name.
Definition: dict.h:210
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Specifies a value which must be present for the module to function.
Definition: dict.h:238
Value of an enumerated attribute.
Definition: dict.h:209
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
static xlat_action_t 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:802
uint32_t fr_hash_string(char const *p)
Definition: hash.c:859
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition: interpret.c:1384
fr_dict_attr_t const * attr_state
Definition: base.c:96
fr_dict_t const * dict_freeradius
Definition: base.c:73
fr_dict_t const * dict_radius
Definition: base.c:74
fr_dict_attr_t const * attr_user_name
Definition: base.c:97
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:845
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:603
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:821
#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_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
void * rctx
Resume ctx that a module previously set.
Definition: module_ctx.h:45
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
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:688
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:278
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition: pair.c:2978
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:1340
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:1684
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:765
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:132
RECV(for_any_server)
Validate a solicit/rebind/confirm message.
Definition: base.c:415
process_radius_auth_t auth
Authentication configuration.
Definition: base.c:154
static int mod_load(void)
Definition: base.c:863
static fr_dict_attr_t const * attr_packet_type
Definition: base.c:64
CONF_SECTION * access_challenge
Definition: base.c:116
static fr_dict_attr_t const * attr_user_password
Definition: base.c:69
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:755
CONF_SECTION * coa_nak
Definition: base.c:125
static virtual_server_compile_t const compile_list[]
Definition: base.c:1093
static xlat_arg_parser_t const xlat_func_radius_secret_verify_args[]
Definition: base.c:785
CONF_SECTION * disconnect_ack
Definition: base.c:128
CONF_SECTION * protocol_error
Definition: base.c:132
CONF_SECTION * new_client
Definition: base.c:134
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:74
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:160
static fr_dict_attr_t const * attr_chap_password
Definition: base.c:62
static const conf_parser_t session_config[]
Definition: base.c:174
CONF_SECTION * coa_request
Definition: base.c:123
static fr_dict_attr_t const * attr_calling_station_id
Definition: base.c:61
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:143
fr_dict_enum_autoload_t process_radius_dict_enum[]
Definition: base.c:101
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: base.c:853
fr_process_module_t process_radius
Definition: base.c:1202
static fr_dict_attr_t const * attr_auth_type
Definition: base.c:55
#define FR_RADIUS_PROCESS_CODE_VALID(_x)
Definition: base.c:164
static void radius_request_pairs_to_reply(request_t *request, process_radius_request_pairs_t *rctx)
Definition: base.c:270
CONF_SECTION * disconnect_nak
Definition: base.c:129
CONF_SECTION * access_accept
Definition: base.c:114
static fr_value_box_t const * enum_auth_type_reject
Definition: base.c:98
static fr_dict_attr_t const * attr_error_cause
Definition: base.c:71
CONF_SECTION * add_client
Definition: base.c:135
static const conf_parser_t auth_config[]
Definition: base.c:182
fr_time_delta_t session_timeout
Maximum time between the last response and next request.
Definition: base.c:140
CONF_SECTION * server_cs
Our virtual server.
Definition: base.c:151
static fr_process_state_t const process_state[]
Definition: base.c:880
CONF_SECTION * access_request
Definition: base.c:113
static fr_dict_attr_t const * attr_proxy_state
Definition: base.c:65
static void radius_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition: base.c:198
static fr_value_box_t const * enum_auth_type_accept
Definition: base.c:97
uint32_t max_session
Maximum ongoing session allowed.
Definition: base.c:141
static fr_dict_attr_t const * attr_nas_port
Definition: base.c:63
CONF_SECTION * status_server
Definition: base.c:121
CONF_SECTION * access_reject
Definition: base.c:115
static fr_dict_attr_t const * attr_acct_status_type
Definition: base.c:60
CONF_SECTION * disconnect_request
Definition: base.c:127
CONF_SECTION * accounting_request
Definition: base.c:118
CONF_SECTION * coa_ack
Definition: base.c:124
CONF_SECTION * do_not_respond
Definition: base.c:131
process_radius_sections_t sections
Pointers to various config sections we need to execute.
Definition: base.c:152
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:241
static fr_dict_attr_t const * attr_service_type
Definition: base.c:66
static fr_dict_attr_t const * attr_original_packet_code
Definition: base.c:70
static const conf_parser_t config[]
Definition: base.c:188
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:147
CONF_SECTION * accounting_response
Definition: base.c:119
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: base.c:842
static fr_dict_attr_t const * attr_module_success_message
Definition: base.c:57
CONF_SECTION * deny_client
Definition: base.c:136
Records fields from the original request so we have a known good copy.
Definition: base.c:159
#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_ma)
Verify a request / response packet.
Definition: base.c:719
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition: base.c:94
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:51
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:1312
#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:516
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:253
#define talloc_get_type_abort_const
Definition: talloc.h:270
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:640
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:3689
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
#define fr_box_ipaddr(_val)
Definition: value.h:287
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:698
#define fr_value_box_list_foreach(_list_head, _iter)
Definition: value.h:199
static size_t char ** out
Definition: value.h:984
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
char const * name
Name of the processing section, such as "recv" or "send".
Processing sections which are allowed in this virtual server.
An xlat calling ctx.
Definition: xlat_ctx.h:42
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:195