The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library 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 GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; 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: ce7c2d49009a03f36cd1df322b8522a13eb4e5ff $
19  *
20  * @file protocols/radius/base.c
21  * @brief Functions to send/receive radius packets.
22  *
23  * @copyright 2000-2003,2006 The FreeRADIUS server project
24  */
25 
26 RCSID("$Id: ce7c2d49009a03f36cd1df322b8522a13eb4e5ff $")
27 
28 #include <fcntl.h>
29 #include <ctype.h>
30 
31 #include "attrs.h"
32 
33 #include <freeradius-devel/io/pair.h>
34 #include <freeradius-devel/util/md5.h>
35 #include <freeradius-devel/util/net.h>
36 #include <freeradius-devel/util/proto.h>
37 #include <freeradius-devel/util/udp.h>
38 #include <freeradius-devel/protocol/radius/freeradius.internal.h>
39 
41 
44 
47  { .out = &dict_freeradius, .proto = "freeradius" },
48  { .out = &dict_radius, .proto = "radius" },
49  { NULL }
50 };
51 
62 
65  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
66  { .out = &attr_packet_authentication_vector, .name = "Packet-Authentication-Vector", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
67  { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
68  { .out = &attr_chargeable_user_identity, .name = "Chargeable-User-Identity", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
69 
70  { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
71  { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
72  { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
73  { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
74  { .out = &attr_nas_filter_rule, .name = "NAS-Filter-Rule", .type = FR_TYPE_STRING, .dict = &dict_radius },
75  { NULL }
76 };
77 
78 /*
79  * Some messages get printed out only in debugging mode.
80  */
81 #define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf_push
82 
85  { L("auth"), FR_RADIUS_CODE_ACCESS_REQUEST },
86  { L("auto"), FR_RADIUS_CODE_UNDEFINED },
87  { L("challenge"), FR_RADIUS_CODE_ACCESS_CHALLENGE },
88  { L("coa"), FR_RADIUS_CODE_COA_REQUEST },
89  { L("disconnect"), FR_RADIUS_CODE_DISCONNECT_REQUEST },
90  { L("status"), FR_RADIUS_CODE_STATUS_SERVER }
91 };
93 
95  "", //!< 0
96  "Access-Request",
97  "Access-Accept",
98  "Access-Reject",
99  "Accounting-Request",
100  "Accounting-Response",
101  "Accounting-Status",
102  "Password-Request",
103  "Password-Accept",
104  "Password-Reject",
105  "Accounting-Message", //!< 10
106  "Access-Challenge",
107  "Status-Server",
108  "Status-Client",
109  "14",
110  "15",
111  "16",
112  "17",
113  "18",
114  "19",
115  "20", //!< 20
116  "Resource-Free-Request",
117  "Resource-Free-Response",
118  "Resource-Query-Request",
119  "Resource-Query-Response",
120  "Alternate-Resource-Reclaim-Request",
121  "NAS-Reboot-Request",
122  "NAS-Reboot-Response",
123  "28",
124  "Next-Passcode",
125  "New-Pin", //!< 30
126  "Terminate-Session",
127  "Password-Expired",
128  "Event-Request",
129  "Event-Response",
130  "35",
131  "36",
132  "37",
133  "38",
134  "39",
135  "Disconnect-Request", //!< 40
136  "Disconnect-ACK",
137  "Disconnect-NAK",
138  "CoA-Request",
139  "CoA-ACK",
140  "CoA-NAK",
141  "46",
142  "47",
143  "48",
144  "49",
145  "IP-Address-Allocate", //!< 50
146  "IP-Address-Release",
147  "Protocol-Error",
148 };
149 
150 
151 /** If we get a reply, the request must come from one of a small
152  * number of packet types.
153  */
158 
160 
163 
166 
168 };
169 
170 int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
171 {
172  int i;
173 
174  if ((code <= 0) || (code >= FR_RADIUS_CODE_MAX)) return -1;
175 
176  for (i = 1; i < FR_RADIUS_CODE_MAX; i++) {
177  allowed[i] |= (allowed_replies[i] == (fr_radius_packet_code_t) code);
178  }
179 
180  return 0;
181 }
182 
183 /** Do Ascend-Send / Recv-Secret calculation.
184  *
185  * The secret is hidden by xoring with a MD5 digest created from
186  * the RADIUS shared secret and the authentication vector.
187  * We put them into MD5 in the reverse order from that used when
188  * encrypting passwords to RADIUS.
189  */
191  char const *secret, uint8_t const *vector)
192 {
193  fr_md5_ctx_t *md5_ctx;
194  size_t i;
195  uint8_t digest[MD5_DIGEST_LENGTH];
196  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
197 
198  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, sizeof(digest));
199 
200  md5_ctx = fr_md5_ctx_alloc_from_list();
201  fr_md5_update(md5_ctx, vector, RADIUS_AUTH_VECTOR_LENGTH);
202  fr_md5_update(md5_ctx, (uint8_t const *) secret, talloc_array_length(secret) - 1);
203  fr_md5_final(digest, md5_ctx);
204  fr_md5_ctx_free_from_list(&md5_ctx);
205 
206  if (inlen > sizeof(digest)) inlen = sizeof(digest);
207  for (i = 0; i < inlen; i++) digest[i] ^= in[i];
208 
209  fr_dbuff_in_memcpy(&work_dbuff, digest, sizeof(digest));
210 
211  return fr_dbuff_set(dbuff, &work_dbuff);
212 }
213 
214 /** Basic validation of RADIUS packet header
215  *
216  * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
217  * consumed when discarding malformed packet.
218  *
219  * @param[in] sockfd we're reading from.
220  * @param[out] src_ipaddr of the packet.
221  * @param[out] src_port of the packet.
222  * @param[out] code Pointer to where to write the packet code.
223  * @return
224  * - -1 on failure.
225  * - 1 on decode error.
226  * - >= RADIUS_HEADER_LENGTH on success. This is the packet length as specified in the header.
227  */
228 ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code)
229 {
230  ssize_t data_len, packet_len;
231  uint8_t header[4];
232 
233  data_len = udp_recv_peek(sockfd, header, sizeof(header), UDP_FLAGS_PEEK, src_ipaddr, src_port);
234  if (data_len < 0) {
235  if ((errno == EAGAIN) || (errno == EINTR)) return 0;
236  return -1;
237  }
238 
239  /*
240  * Too little data is available, discard the packet.
241  */
242  if (data_len < 4) {
243  char buffer[INET6_ADDRSTRLEN];
244 
245  FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zu bytes", data_len);
246 invalid:
247  FR_DEBUG_STRERROR_PRINTF("Invalid data from %s",
248  inet_ntop(src_ipaddr->af, &src_ipaddr->addr, buffer, sizeof(buffer)));
249  (void) udp_recv_discard(sockfd);
250 
251  return 0;
252  }
253 
254  /*
255  * See how long the packet says it is.
256  */
257  packet_len = (header[2] * 256) + header[3];
258 
259  /*
260  * The length in the packet says it's less than
261  * a RADIUS header length: discard it.
262  */
263  if (packet_len < RADIUS_HEADER_LENGTH) {
264  FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HEADER_LENGTH) " bytes of packet "
265  "data, got %zu bytes", packet_len);
266  goto invalid;
267  }
268 
269  /*
270  * Enforce RFC requirements, for sanity.
271  * Anything after 4k will be discarded.
272  */
273  if (packet_len > MAX_PACKET_LEN) {
274  FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
275  STRINGIFY(MAX_PACKET_LEN) " bytes, got %zu bytes", packet_len);
276  goto invalid;
277  }
278 
279  *code = header[0];
280 
281  /*
282  * The packet says it's this long, but the actual UDP
283  * size could still be smaller.
284  */
285  return packet_len;
286 }
287 
288 /** Sign a previously encoded packet
289  *
290  * Calculates the request/response authenticator for packets which need it, and fills
291  * in the message-authenticator value if the attribute is present in the encoded packet.
292  *
293  * @param[in,out] packet (request or response).
294  * @param[in] vector original packet vector to use
295  * @param[in] secret to sign the packet with.
296  * @param[in] secret_len The length of the secret.
297  * @return
298  * - <0 on error
299  * - 0 on success
300  */
301 int fr_radius_sign(uint8_t *packet, uint8_t const *vector,
302  uint8_t const *secret, size_t secret_len)
303 {
304  uint8_t *msg, *end;
305  size_t packet_len = fr_nbo_to_uint16(packet + 2);
306 
307  /*
308  * No real limit on secret length, this is just
309  * to catch uninitialised fields.
310  */
311  if (!fr_cond_assert(secret_len <= UINT16_MAX)) {
312  fr_strerror_printf("Secret is too long. Expected <= %u, got %zu", UINT16_MAX, secret_len);
313  return -1;
314  }
315 
316  if (packet_len < RADIUS_HEADER_LENGTH) {
317  fr_strerror_const("Packet must be encoded before calling fr_radius_sign()");
318  return -1;
319  }
320 
321  /*
322  * Find Message-Authenticator. Its value has to be
323  * calculated before we calculate the Request
324  * Authenticator or the Response Authenticator.
325  */
326  msg = packet + RADIUS_HEADER_LENGTH;
327  end = packet + packet_len;
328 
329  while (msg < end) {
330  if ((end - msg) < 2) goto invalid_attribute;
331 
332  if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
333  if (msg[1] < 2) goto invalid_attribute;
334 
335  if ((msg + msg[1]) > end) {
336  invalid_attribute:
337  fr_strerror_printf("Invalid attribute at offset %zd", msg - packet);
338  return -1;
339  }
340  msg += msg[1];
341  continue;
342  }
343 
344  if (msg[1] < 18) {
345  fr_strerror_const("Message-Authenticator is too small");
346  return -1;
347  }
348 
349  switch (packet[0]) {
353  memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
354  break;
355 
364  if (!vector) goto need_original;
365  memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
366  break;
367 
370  /* packet + 4 MUST be the Request Authenticator filled with random data */
371  break;
372 
373  default:
374  goto bad_packet;
375  }
376 
377  /*
378  * Force Message-Authenticator to be zero,
379  * calculate the HMAC, and put it into the
380  * Message-Authenticator attribute.
381  */
382  memset(msg + 2, 0, RADIUS_AUTH_VECTOR_LENGTH);
383  fr_hmac_md5(msg + 2, packet, packet_len, secret, secret_len);
384  break;
385  }
386 
387  /*
388  * Initialize the request authenticator.
389  */
390  switch (packet[0]) {
394  memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
395  break;
396 
406  if (!vector) {
407  need_original:
408  fr_strerror_const("Cannot sign response packet without a request packet");
409  return -1;
410  }
411  memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
412  break;
413 
414  /*
415  * The Request Authenticator is random numbers.
416  * We don't need to sign anything else, so
417  * return.
418  */
421  return 0;
422 
423  default:
424  bad_packet:
425  fr_strerror_printf("Cannot sign unknown packet code %u", packet[0]);
426  return -1;
427  }
428 
429  /*
430  * Request / Response Authenticator = MD5(packet + secret)
431  */
432  {
433  fr_md5_ctx_t *md5_ctx;
434 
435  md5_ctx = fr_md5_ctx_alloc_from_list();
436  fr_md5_update(md5_ctx, packet, packet_len);
437  fr_md5_update(md5_ctx, secret, secret_len);
438  fr_md5_final(packet + 4, md5_ctx);
439  fr_md5_ctx_free_from_list(&md5_ctx);
440  }
441 
442  return 0;
443 }
444 
445 
446 /** See if the data pointed to by PTR is a valid RADIUS packet.
447  *
448  * @param[in] packet to check.
449  * @param[in,out] packet_len_p The size of the packet data.
450  * @param[in] max_attributes to allow in the packet.
451  * @param[in] require_ma whether we require Message-Authenticator.
452  * @param[in] reason if not NULL, will have the failure reason written to where it points.
453  * @return
454  * - True on success.
455  * - False on failure.
456  */
457 bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p,
458  uint32_t max_attributes, bool require_ma, decode_fail_t *reason)
459 {
460  uint8_t const *attr, *end;
461  size_t totallen;
462  bool seen_ma = false;
463  uint32_t num_attributes;
465  size_t packet_len = *packet_len_p;
466 
467  /*
468  * Check for packets smaller than the packet header.
469  *
470  * RFC 2865, Section 3., subsection 'length' says:
471  *
472  * "The minimum length is 20 ..."
473  */
474  if (packet_len < RADIUS_HEADER_LENGTH) {
475  FR_DEBUG_STRERROR_PRINTF("packet is too short (received %zu < minimum 20)",
476  packet_len);
478  goto finish;
479  }
480 
481 
482  /*
483  * Check for packets with mismatched size.
484  * i.e. We've received 128 bytes, and the packet header
485  * says it's 256 bytes long.
486  */
487  totallen = fr_nbo_to_uint16(packet + 2);
488 
489  /*
490  * Code of 0 is not understood.
491  * Code of 16 or greater is not understood.
492  */
493  if ((packet[0] == 0) ||
494  (packet[0] >= FR_RADIUS_CODE_MAX)) {
495  FR_DEBUG_STRERROR_PRINTF("unknown packet code %d", packet[0]);
497  goto finish;
498  }
499 
500  /*
501  * Message-Authenticator is required in Status-Server
502  * packets, otherwise they can be trivially forged.
503  */
504  if (packet[0] == FR_RADIUS_CODE_STATUS_SERVER) require_ma = true;
505 
506  /*
507  * Repeat the length checks. This time, instead of
508  * looking at the data we received, look at the value
509  * of the 'length' field inside of the packet.
510  *
511  * Check for packets smaller than the packet header.
512  *
513  * RFC 2865, Section 3., subsection 'length' says:
514  *
515  * "The minimum length is 20 ..."
516  */
517  if (totallen < RADIUS_HEADER_LENGTH) {
518  FR_DEBUG_STRERROR_PRINTF("length in header is too small (length %zu < minimum 20)",
519  totallen);
521  goto finish;
522  }
523 
524  /*
525  * And again, for the value of the 'length' field.
526  *
527  * RFC 2865, Section 3., subsection 'length' says:
528  *
529  * " ... and maximum length is 4096."
530  *
531  * HOWEVER. This requirement is for the network layer.
532  * If the code gets here, we assume that a well-formed
533  * packet is an OK packet.
534  *
535  * We allow both the UDP data length, and the RADIUS
536  * "length" field to contain up to 64K of data.
537  */
538 
539  /*
540  * RFC 2865, Section 3., subsection 'length' says:
541  *
542  * "If the packet is shorter than the Length field
543  * indicates, it MUST be silently discarded."
544  *
545  * i.e. No response to the NAS.
546  */
547  if (totallen > packet_len) {
548  FR_DEBUG_STRERROR_PRINTF("packet is truncated (received %zu < packet header length of %zu)",
549  packet_len, totallen);
551  goto finish;
552  }
553 
554  /*
555  * RFC 2865, Section 3., subsection 'length' says:
556  *
557  * "Octets outside the range of the Length field MUST be
558  * treated as padding and ignored on reception."
559  */
560  if (totallen < packet_len) {
561  *packet_len_p = packet_len = totallen;
562  }
563 
564  /*
565  * Walk through the packet's attributes, ensuring that
566  * they add up EXACTLY to the size of the packet.
567  *
568  * If they don't, then the attributes either under-fill
569  * or over-fill the packet. Any parsing of the packet
570  * is impossible, and will result in unknown side effects.
571  *
572  * This would ONLY happen with buggy RADIUS implementations,
573  * or with an intentional attack. Either way, we do NOT want
574  * to be vulnerable to this problem.
575  */
576  attr = packet + RADIUS_HEADER_LENGTH;
577  end = packet + packet_len;
578  num_attributes = 0;
579 
580  while (attr < end) {
581  /*
582  * We need at least 2 bytes to check the
583  * attribute header.
584  */
585  if ((end - attr) < 2) {
586  FR_DEBUG_STRERROR_PRINTF("attribute header overflows the packet");
587  failure = DECODE_FAIL_HEADER_OVERFLOW;
588  goto finish;
589  }
590 
591  /*
592  * Attribute number zero is NOT defined.
593  */
594  if (attr[0] == 0) {
595  FR_DEBUG_STRERROR_PRINTF("invalid attribute 0 at offset %zd", attr - packet);
597  goto finish;
598  }
599 
600  /*
601  * Attributes are at LEAST as long as the ID & length
602  * fields. Anything shorter is an invalid attribute.
603  */
604  if (attr[1] < 2) {
605  FR_DEBUG_STRERROR_PRINTF("attribute %u is too short at offset %zd",
606  attr[0], attr - packet);
608  goto finish;
609  }
610 
611  /*
612  * If there are fewer bytes in the packet than in the
613  * attribute, it's a bad packet.
614  */
615  if ((attr + attr[1]) > end) {
616  FR_DEBUG_STRERROR_PRINTF("attribute %u data overflows the packet starting at offset %zd",
617  attr[0], attr - packet);
619  goto finish;
620  }
621 
622  /*
623  * Sanity check the attributes for length.
624  */
625  switch (attr[0]) {
626  default: /* don't do anything by default */
627  break;
628 
629  /*
630  * If there's an EAP-Message, we require
631  * a Message-Authenticator.
632  */
633  case FR_EAP_MESSAGE:
634  require_ma = true;
635  break;
636 
637  case FR_MESSAGE_AUTHENTICATOR:
638  if (attr[1] != 2 + RADIUS_AUTH_VECTOR_LENGTH) {
639  FR_DEBUG_STRERROR_PRINTF("Message-Authenticator has invalid length (%d != 18) at offset %zd",
640  attr[1] - 2, attr - packet);
642  goto finish;
643  }
644  seen_ma = true;
645  break;
646  }
647 
648  attr += attr[1];
649  num_attributes++; /* seen one more attribute */
650  }
651 
652  /*
653  * If the attributes add up to a packet, it's allowed.
654  *
655  * If not, we complain, and throw the packet away.
656  */
657  if (attr != end) {
658  FR_DEBUG_STRERROR_PRINTF("attributes do NOT exactly fill the packet");
660  goto finish;
661  }
662 
663  /*
664  * If we're configured to look for a maximum number of
665  * attributes, and we've seen more than that maximum,
666  * then throw the packet away, as a possible DoS.
667  */
668  if ((max_attributes > 0) &&
669  (num_attributes > max_attributes)) {
670  FR_DEBUG_STRERROR_PRINTF("Possible DoS attack - too many attributes in request (received %d, max %d are allowed).",
671  num_attributes, max_attributes);
673  goto finish;
674  }
675 
676  /*
677  * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
678  *
679  * A packet with an EAP-Message attribute MUST also have
680  * a Message-Authenticator attribute.
681  *
682  * A Message-Authenticator all by itself is OK, though.
683  *
684  * Similarly, Status-Server packets MUST contain
685  * Message-Authenticator attributes.
686  */
687  if (require_ma && !seen_ma) {
688  FR_DEBUG_STRERROR_PRINTF("we require Message-Authenticator attribute, but it is not in the packet");
689  failure = DECODE_FAIL_MA_MISSING;
690  goto finish;
691  }
692 
693 finish:
694 
695  if (reason) {
696  *reason = failure;
697  }
698  return (failure == DECODE_FAIL_NONE);
699 }
700 
701 
702 /** Verify a request / response packet
703  *
704  * This function does its work by calling fr_radius_sign(), and then
705  * comparing the signature in the packet with the one we calculated.
706  * If they differ, there's a problem.
707  *
708  * @param[in] packet the raw RADIUS packet (request or response)
709  * @param[in] vector the original packet vector
710  * @param[in] secret the shared secret
711  * @param[in] secret_len the length of the secret
712  * @param[in] require_ma whether we require Message-Authenticator.
713  * @return
714  * - -2 if the message authenticator or request authenticator was invalid.
715  * - -1 if we were unable to verify the shared secret, or the packet
716  * was in some other way malformed.
717  * - 0 on success.
718  */
719 int fr_radius_verify(uint8_t *packet, uint8_t const *vector,
720  uint8_t const *secret, size_t secret_len, bool require_ma)
721 {
722  bool found_ma;
723  int rcode;
724  int code;
725  uint8_t *msg, *end;
726  size_t packet_len = fr_nbo_to_uint16(packet + 2);
727  uint8_t request_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
728  uint8_t message_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
729 
730  if (packet_len < RADIUS_HEADER_LENGTH) {
731  fr_strerror_printf("invalid packet length %zd", packet_len);
732  return -1;
733  }
734 
735  code = packet[0];
736  if (!code || (code >= FR_RADIUS_CODE_MAX)) {
737  fr_strerror_printf("Unknown reply code %d", code);
738  return -1;
739  }
740 
741  memcpy(request_authenticator, packet + 4, sizeof(request_authenticator));
742 
743  /*
744  * Find Message-Authenticator. Its value has to be
745  * calculated before we calculate the Request
746  * Authenticator or the Response Authenticator.
747  */
748  msg = packet + RADIUS_HEADER_LENGTH;
749  end = packet + packet_len;
750  found_ma = false;
751 
752  while (msg < end) {
753  if ((end - msg) < 2) goto invalid_attribute;
754 
755  if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
756  if (msg[1] < 2) goto invalid_attribute;
757 
758  if ((msg + msg[1]) > end) {
759  invalid_attribute:
760  fr_strerror_printf("invalid attribute at offset %zd", msg - packet);
761  return -1;
762  }
763  msg += msg[1];
764  continue;
765  }
766 
767  if (msg[1] < 18) {
768  fr_strerror_const("too small Message-Authenticator");
769  return -1;
770  }
771 
772  /*
773  * Found it, save a copy.
774  */
775  memcpy(message_authenticator, msg + 2, sizeof(message_authenticator));
776  found_ma = true;
777  break;
778  }
779 
780  if ((packet[0] == FR_RADIUS_CODE_ACCESS_REQUEST) &&
781  require_ma && !found_ma) {
782  fr_strerror_const("Access-Request is missing the required Message-Authenticator attribute");
783  return -1;
784  }
785 
786  /*
787  * Implement verification as a signature, followed by
788  * checking our signature against the sent one. This is
789  * slightly more CPU work than having verify-specific
790  * functions, but it ends up being cleaner in the code.
791  */
792  rcode = fr_radius_sign(packet, vector, secret, secret_len);
793  if (rcode < 0) {
794  fr_strerror_const_push("Failed calculating correct authenticator");
795  return -1;
796  }
797 
798  /*
799  * Check the Message-Authenticator first.
800  *
801  * If it's invalid, restore the original
802  * Message-Authenticator and Request Authenticator
803  * fields.
804  */
805  if ((msg < end) &&
806  (fr_digest_cmp(message_authenticator, msg + 2, sizeof(message_authenticator)) != 0)) {
807  memcpy(msg + 2, message_authenticator, sizeof(message_authenticator));
808  memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
809 
810  fr_strerror_const("invalid Message-Authenticator (shared secret is incorrect)");
811  return -2;
812  }
813 
814  /*
815  * These are random numbers, so there's no point in
816  * comparing them.
817  */
818  if ((packet[0] == FR_RADIUS_CODE_ACCESS_REQUEST) || (packet[0] == FR_RADIUS_CODE_STATUS_SERVER)) {
819  return 0;
820  }
821 
822  /*
823  * Check the Request Authenticator.
824  */
825  if (fr_digest_cmp(request_authenticator, packet + 4, sizeof(request_authenticator)) != 0) {
826  memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
827  if (vector) {
828  fr_strerror_const("invalid Response Authenticator (shared secret is incorrect)");
829  } else {
830  fr_strerror_const("invalid Request Authenticator (shared secret is incorrect)");
831  }
832  return -2;
833  }
834 
835  return 0;
836 }
837 
838 void *fr_radius_next_encodable(fr_dlist_head_t *list, void *current, void *uctx);
839 
840 void *fr_radius_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
841 {
842  fr_pair_t *c = current;
843  fr_dict_t *dict = talloc_get_type_abort(uctx, fr_dict_t);
844 
845  while ((c = fr_dlist_next(list, c))) {
846  PAIR_VERIFY(c);
847  if ((c->da->dict == dict) &&
848  (!c->da->flags.internal || ((c->da->attr > FR_TAG_BASE) && (c->da->attr < (FR_TAG_BASE + 0x20))))) {
849  break;
850  }
851  }
852 
853  return c;
854 }
855 
856 
857 /** Encode VPS into a raw RADIUS packet.
858  *
859  */
860 ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *original,
861  char const *secret, size_t secret_len, int code, int id, fr_pair_list_t *vps)
862 {
863  return fr_radius_encode_dbuff(&FR_DBUFF_TMP(packet, packet_len), original, secret, secret_len, code, id, vps);
864 }
865 
868  // can be in Access-Accept
869  [ FR_RADIUS_CODE_ACCESS_REJECT ] = true,
871 
874 
875  [ FR_RADIUS_CODE_STATUS_SERVER ] = true,
876 
877  [ FR_RADIUS_CODE_COA_ACK ] = true,
878  [ FR_RADIUS_CODE_COA_NAK ] = true,
879 
883 
885 };
886 
888  char const *secret, size_t secret_len, int code, int id, fr_pair_list_t *vps)
889 {
890  ssize_t slen;
891  fr_pair_t const *vp;
892  fr_dcursor_t cursor;
893  fr_radius_ctx_t common_ctx = {};
894  fr_radius_encode_ctx_t packet_ctx = {};
895  fr_dbuff_t work_dbuff, length_dbuff;
896 
897  common_ctx.secret = secret;
898  common_ctx.secret_length = secret_len;
899 
900  packet_ctx.common = &common_ctx;
901  packet_ctx.request_authenticator = common_ctx.vector;
902  packet_ctx.rand_ctx.a = fr_rand();
903  packet_ctx.rand_ctx.b = fr_rand();
905 
906  /*
907  * The RADIUS header can't do more than 64K of data.
908  */
909  work_dbuff = FR_DBUFF_MAX(dbuff, 65535);
910 
911  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, code, id);
912  length_dbuff = FR_DBUFF(&work_dbuff);
914 
915  switch (code) {
918  /*
919  * Callers in these cases have preloaded the buffer with the authentication vector.
920  */
921  FR_DBUFF_OUT_MEMCPY_RETURN(common_ctx.vector, &work_dbuff, sizeof(common_ctx.vector));
922  break;
923 
933  if (!original) {
934  fr_strerror_const("Cannot encode response without request");
935  return -1;
936  }
937  memcpy(common_ctx.vector, original + 4, sizeof(common_ctx.vector));
939  break;
940 
943  /*
944  * Tunnel-Password encoded attributes are allowed
945  * in CoA-Request packets, by RFC 5176 Section
946  * 3.6. HOWEVER, the tunnel passwords are
947  * "encrypted" using the Request Authenticator,
948  * which is all zeros! That makes them much
949  * easier to decrypt. The only solution here is
950  * to say "don't do that!"
951  */
953  memset(common_ctx.vector, 0, sizeof(common_ctx.vector));
955  break;
956 
957  default:
958  fr_strerror_printf("Cannot encode unknown packet code %d", code);
959  return -1;
960  }
961 
962  /*
963  * If we're sending Protocol-Error, add in
964  * Original-Packet-Code manually. If the user adds it
965  * later themselves, well, too bad.
966  */
967  if (code == FR_RADIUS_CODE_PROTOCOL_ERROR) {
968  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_EXTENDED_ATTRIBUTE_1, 0x07, 0x04 /* Original-Packet-Code */,
969  0x00, 0x00, 0x00, original[0]);
970  }
971 
972  /*
973  * Loop over the reply attributes for the packet.
974  */
976  while ((vp = fr_dcursor_current(&cursor))) {
977  PAIR_VERIFY(vp);
978 
979  /*
980  * Encode an individual VP
981  */
982  slen = fr_radius_encode_pair(&work_dbuff, &cursor, &packet_ctx);
983  if (slen < 0) return slen;
984  } /* done looping over all attributes */
985 
986  /*
987  * Fill in the length field we zeroed out earlier.
988  *
989  */
990  fr_dbuff_in(&length_dbuff, (uint16_t) (fr_dbuff_used(&work_dbuff)));
991 
992  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "%s encoded packet", __FUNCTION__);
993 
994  return fr_dbuff_set(dbuff, &work_dbuff);
995 }
996 
998  uint8_t *packet, size_t packet_len,
999  fr_radius_decode_ctx_t *decode_ctx)
1000 {
1001  ssize_t slen;
1002  uint8_t const *attr, *end;
1003  static const uint8_t zeros[RADIUS_AUTH_VECTOR_LENGTH] = {};
1004 
1005  if (!decode_ctx->request_authenticator) {
1006  switch (packet[0]) {
1009  decode_ctx->request_authenticator = packet + 4;
1010  break;
1011 
1015  decode_ctx->request_authenticator = zeros;
1016  break;
1017 
1018  default:
1019  fr_strerror_const("No authentication vector passed for packet decode");
1020  return -1;
1021  }
1022  }
1023 
1024  if (decode_ctx->request_code) {
1025  int code = packet[0];
1026 
1027  fr_assert(code < FR_RADIUS_CODE_MAX); /* checked by fr_radius_ok() */
1028  fr_assert(decode_ctx->request_code < FR_RADIUS_CODE_MAX); /* checked by fr_radius_ok() */
1029 
1030  if (!allowed_replies[code]) {
1031  fr_strerror_printf("%s packet received unknown reply code %s",
1034  }
1035 
1036  /*
1037  * Protocol error can reply to any packet.
1038  *
1039  * Status-Server can get any reply.
1040  *
1041  * Otherwise the reply code must be associated with the request code we sent.
1042  */
1043  if ((code != FR_RADIUS_CODE_PROTOCOL_ERROR) && (decode_ctx->request_code != FR_RADIUS_CODE_STATUS_SERVER) &&
1044  (allowed_replies[code] != decode_ctx->request_code)) {
1045  fr_strerror_printf("%s packet received invalid reply code %s",
1048  }
1049  }
1050 
1051  /*
1052  * We can skip verification for dynamic client checks, and where packets are unsigned as with
1053  * RADIUS/1.1.
1054  */
1055  if (decode_ctx->verify) {
1056  if (!decode_ctx->request_authenticator) decode_ctx->request_authenticator = zeros;
1057 
1058  if (fr_radius_verify(packet, decode_ctx->request_authenticator,
1059  (uint8_t const *) decode_ctx->common->secret, decode_ctx->common->secret_length,
1060  decode_ctx->require_message_authenticator) < 0) {
1061  return -1;
1062  }
1063  }
1064 
1065  attr = packet + 20;
1066  end = packet + packet_len;
1067 
1068  /*
1069  * The caller MUST have called fr_radius_ok() first. If
1070  * he doesn't, all hell breaks loose.
1071  */
1072  while (attr < end) {
1073  slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), decode_ctx);
1074  if (slen < 0) return slen;
1075 
1076  /*
1077  * If slen is larger than the room in the packet,
1078  * all kinds of bad things happen.
1079  */
1080  if (!fr_cond_assert(slen <= (end - attr))) {
1081  return -slen;
1082  }
1083 
1084  attr += slen;
1085  talloc_free_children(decode_ctx->tmp_ctx);
1086  }
1087 
1088  /*
1089  * We've parsed the whole packet, return that.
1090  */
1091  return packet_len;
1092 }
1093 
1094 /** Simple wrapper for callers who just need a shared secret
1095  *
1096  */
1098  uint8_t *packet, size_t packet_len,
1099  uint8_t const *vector, char const *secret)
1100 {
1101  ssize_t rcode;
1102  fr_radius_ctx_t common_ctx = {};
1103  fr_radius_decode_ctx_t packet_ctx = {};
1104 
1105  common_ctx.secret = secret;
1106  common_ctx.secret_length = strlen(secret);
1107 
1108  packet_ctx.common = &common_ctx;
1109  packet_ctx.tmp_ctx = talloc(ctx, uint8_t);
1110  packet_ctx.request_authenticator = vector;
1111  packet_ctx.end = packet + packet_len;
1112 
1113  rcode = fr_radius_decode(ctx, out, packet, packet_len, &packet_ctx);
1114  talloc_free(packet_ctx.tmp_ctx);
1115 
1116  return rcode;
1117 }
1118 
1120 {
1121  if (instance_count > 0) {
1122  instance_count++;
1123  return 0;
1124  }
1125 
1126  instance_count++;
1127 
1129  fail:
1130  instance_count--;
1131  return -1;
1132  }
1133 
1136  goto fail;
1137  }
1138 
1139  return 0;
1140 }
1141 
1143 {
1145 
1146  if (--instance_count > 0) return;
1147 
1149 }
1150 
1152  { L("long-extended"), FLAG_LONG_EXTENDED_ATTR },
1153  { L("extended"), FLAG_EXTENDED_ATTR },
1154  { L("concat"), FLAG_CONCAT },
1155  { L("has_tag"), FLAG_HAS_TAG },
1156  { L("abinary"), FLAG_ABINARY },
1157  { L("has_tag,encrypt=2"), FLAG_TAGGED_TUNNEL_PASSWORD },
1158 
1159  { L("encrypt=1"), FLAG_ENCRYPT_USER_PASSWORD },
1160  { L("encrypt=2"), FLAG_ENCRYPT_TUNNEL_PASSWORD },
1161  { L("encrypt=3"), FLAG_ENCRYPT_ASCEND_SECRET },
1162 
1163  /*
1164  * And some humanly-readable names
1165  */
1166  { L("encrypt=User-Password"), FLAG_ENCRYPT_USER_PASSWORD },
1167  { L("encrypt=Tunnel-Password"), FLAG_ENCRYPT_TUNNEL_PASSWORD },
1168  { L("encrypt=Ascend-Secret"), FLAG_ENCRYPT_ASCEND_SECRET },
1169 };
1170 
1172  UNUSED char const *name, UNUSED int attr, fr_type_t type, fr_dict_attr_flags_t *flags)
1173 {
1174  if (parent->type == FR_TYPE_STRUCT) {
1175  if (flag_extended(flags)) {
1176  fr_strerror_const("Attributes of type 'extended' cannot be used inside of a 'struct'");
1177  return false;
1178  }
1179 
1180  /*
1181  * The "extra" flag signifies that the subtype
1182  * field is being used by the dictionaries
1183  * itself, for key fields, etc.
1184  */
1185  if (flags->extra) return true;
1186 
1187  /*
1188  * All other flags are invalid inside of a struct.
1189  */
1190  if (flags->subtype) {
1191  fr_strerror_const("Attributes inside of a 'struct' MUST NOT have flags set");
1192  return false;
1193  }
1194 
1195  return true;
1196  }
1197 
1198  /*
1199  * The 'extra flag is only for inside of structs and TLVs
1200  * with refs. It shouldn't appear anywhere else.
1201  */
1202  if (flags->extra) {
1203  fr_strerror_const("Unsupported extension.");
1204  return false;
1205  }
1206 
1207  if (flags->length > 253) {
1208  fr_strerror_printf("Attributes cannot be more than 253 octets in length");
1209  return false;
1210  }
1211 
1212  /*
1213  * No special flags, so we're OK.
1214  *
1215  * If there is a subtype, it can only be of one kind.
1216  */
1217  if (!flags->subtype) return true;
1218 
1219  if (flags->subtype > FLAG_ENCRYPT_ASCEND_SECRET) {
1220  fr_strerror_printf("Invalid flag value %u", flags->subtype);
1221  return false;
1222  }
1223 
1224  /*
1225  * Secret things are secret.
1226  */
1227  if (flags->subtype > FLAG_TAGGED_TUNNEL_PASSWORD) {
1228  flags->secret = true;
1229  }
1230 
1231  if (flag_concat(flags)) {
1232  if (!parent->flags.is_root) {
1233  fr_strerror_const("Attributes with the 'concat' flag MUST be at the root of the dictionary");
1234  return false;
1235  }
1236 
1237  if (type != FR_TYPE_OCTETS) {
1238  fr_strerror_const("Attributes with the 'concat' flag MUST be of data type 'octets'");
1239  return false;
1240  }
1241 
1242  return true; /* can't use any other flag */
1243  }
1244 
1245  /*
1246  * Tagged attributes can only be of two data types. They
1247  * can, however, be VSAs.
1248  */
1249  if (flag_has_tag(flags)) {
1250  if ((type != FR_TYPE_UINT32) && (type != FR_TYPE_STRING)) {
1251  fr_strerror_printf("The 'has_tag' flag can only be used for attributes of type 'integer' "
1252  "or 'string'");
1253  return false;
1254  }
1255 
1256  if (!(parent->flags.is_root ||
1257  ((parent->type == FR_TYPE_VENDOR) &&
1258  (parent->parent && parent->parent->type == FR_TYPE_VSA)))) {
1259  fr_strerror_const("The 'has_tag' flag can only be used with RFC and VSA attributes");
1260  return false;
1261  }
1262 
1263  return true;
1264  }
1265 
1266  if (flag_extended(flags)) {
1267  if (type != FR_TYPE_TLV) {
1268  fr_strerror_const("The 'long' or 'extended' flag can only be used for attributes of type 'tlv'");
1269  return false;
1270  }
1271 
1272  if (!parent->flags.is_root) {
1273  fr_strerror_const("The 'long' flag can only be used for top-level RFC attributes");
1274  return false;
1275  }
1276 
1277  return true;
1278  }
1279 
1280  /*
1281  * Stupid hacks for MS-CHAP-MPPE-Keys. The User-Password
1282  * encryption method has no provisions for encoding the
1283  * length of the data. For User-Password, the data is
1284  * (presumably) all printable non-zero data. For
1285  * MS-CHAP-MPPE-Keys, the data is binary crap. So... we
1286  * MUST specify a length in the dictionary.
1287  */
1288  if ((flags->subtype == FLAG_ENCRYPT_USER_PASSWORD) && (type != FR_TYPE_STRING)) {
1289  if (type != FR_TYPE_OCTETS) {
1290  fr_strerror_printf("The 'encrypt=1' flag can only be used with "
1291  "attributes of type 'string'");
1292  return false;
1293  }
1294 
1295  if (flags->length == 0) {
1296  fr_strerror_printf("The 'encrypt=1' flag MUST be used with an explicit length for "
1297  "'octets' data types");
1298  return false;
1299  }
1300  }
1301 
1302  switch (type) {
1303  case FR_TYPE_STRING:
1304  break;
1305 
1306  case FR_TYPE_TLV:
1307  case FR_TYPE_IPV4_ADDR:
1308  case FR_TYPE_UINT32:
1309  case FR_TYPE_OCTETS:
1310  if (flags->subtype != FLAG_ENCRYPT_ASCEND_SECRET) break;
1311  FALL_THROUGH;
1312 
1313  default:
1314  fr_strerror_printf("The 'encrypt' flag cannot be used with attributes of type '%s'",
1315  fr_type_to_str(type));
1316  return false;
1317  }
1318 
1319  return true;
1320 }
1321 
1324  .name = "radius",
1325  .default_type_size = 1,
1326  .default_type_length = 1,
1327  .subtype_table = subtype_table,
1328  .subtype_table_len = NUM_ELEMENTS(subtype_table),
1329  .attr_valid = attr_valid,
1330 
1331  .init = fr_radius_global_init,
1332  .free = fr_radius_global_free,
1333 
1334  .decode = fr_radius_decode_foreign,
1335  .encode = fr_radius_encode_foreign,
1336 };
static int const char char buffer[256]
Definition: acutest.h:574
log_entry msg
Definition: acutest.h:794
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define STRINGIFY(x)
Definition: build.h:195
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition: dbuff.h:762
#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat)
Extend if we're below _lowat and return if we can't extend above _lowat.
Definition: dbuff.h:668
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:893
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
Definition: dbuff.h:1503
#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen)
Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff.
Definition: dbuff.h:1744
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition: dbuff.h:1377
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition: dbuff.h:1345
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition: dbuff.h:1562
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition: dbuff.h:1580
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition: dbuff.h:301
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition: dbuff.h:1467
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
fr_radius_packet_code_t
RADIUS packet codes.
Definition: defs.h:31
@ 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_MAX
Maximum possible protocol code.
Definition: defs.h:53
@ 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_UNDEFINED
Packet code has not been set.
Definition: defs.h:32
@ 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
#define MAX_PACKET_LEN
Definition: defs.h:68
static int sockfd
Definition: dhcpclient.c:56
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
unsigned int secret
this attribute should be omitted in debug mode
Definition: dict.h:100
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition: dict.h:109
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
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:3647
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
static fr_slen_t in
Definition: dict.h:645
char const * name
name of this protocol
Definition: dict.h:342
uint8_t subtype
protocol-specific values, OR key fields
Definition: dict.h:118
uint8_t length
length of the attribute
Definition: dict.h:124
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Values of the encryption flags.
Definition: merged_model.c:139
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:341
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
Head of a doubly linked list.
Definition: dlist.h:51
int fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal MD5 implementation.
Definition: hmac_md5.c:119
int af
Address family.
Definition: inet.h:64
union fr_ipaddr_t::@121 addr
IPv4/6 prefix.
Definition: merged_model.c:272
fr_dict_attr_t const * attr_state
Definition: base.c:96
fr_dict_attr_t const * attr_eap_message
Definition: base.c:90
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_message_authenticator
Definition: base.c:88
talloc_free(reap)
int udp_recv_discard(int sockfd)
Discard the next UDP packet.
Definition: udp.c:76
ssize_t udp_recv_peek(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Peek at the header of a UDP packet.
Definition: udp.c:96
fr_md5_update_t fr_md5_update
Definition: md5.c:450
fr_md5_final_t fr_md5_final
Definition: md5.c:451
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition: md5.c:530
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition: md5.c:485
void fr_md5_ctx_t
Definition: md5.h:28
#define MD5_DIGEST_LENGTH
Definition: merged_model.c:248
unsigned short uint16_t
Definition: merged_model.c:31
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ 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_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition: misc.c:463
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:443
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition: nbo.h:137
#define RADIUS_HEADER_LENGTH
Definition: net.h:80
#define RADIUS_AUTH_VECTOR_LENGTH
Definition: net.h:89
static uint8_t const zeros[6]
Definition: base.c:93
fr_dict_attr_t const * attr_packet_type
Definition: base.c:50
fr_dict_protocol_t libfreeradius_radius_dict_protocol
Definition: base.c:1323
fr_dict_autoload_t libfreeradius_radius_dict[]
Definition: base.c:46
fr_dict_attr_t const * attr_nas_filter_rule
Definition: base.c:61
static const bool disallow_tunnel_passwords[FR_RADIUS_CODE_MAX]
Definition: base.c:866
void * fr_radius_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
Definition: base.c:840
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
fr_dict_attr_t const * attr_packet_authentication_vector
Definition: base.c:53
static const fr_radius_packet_code_t allowed_replies[FR_RADIUS_CODE_MAX]
If we get a reply, the request must come from one of a small number of packet types.
Definition: base.c:154
ssize_t fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen, char const *secret, uint8_t const *vector)
Do Ascend-Send / Recv-Secret calculation.
Definition: base.c:190
ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, fr_radius_decode_ctx_t *decode_ctx)
Definition: base.c:997
static uint32_t instance_count
Definition: base.c:40
int fr_radius_sign(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len)
Sign a previously encoded packet.
Definition: base.c:301
fr_dict_attr_t const * attr_raw_attribute
Definition: base.c:54
fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[]
Definition: base.c:64
bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, uint32_t max_attributes, bool require_ma, decode_fail_t *reason)
See if the data pointed to by PTR is a valid RADIUS packet.
Definition: base.c:457
fr_dict_attr_t const * attr_chap_challenge
Definition: base.c:55
fr_dict_attr_t const * attr_vendor_specific
Definition: base.c:60
ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *original, char const *secret, size_t secret_len, int code, int id, fr_pair_list_t *vps)
Encode VPS into a raw RADIUS packet.
Definition: base.c:860
static bool attr_valid(UNUSED fr_dict_t *dict, fr_dict_attr_t const *parent, UNUSED char const *name, UNUSED int attr, fr_type_t type, fr_dict_attr_flags_t *flags)
Definition: base.c:1171
int fr_radius_global_init(void)
Definition: base.c:1119
size_t fr_radius_request_name_table_len
Definition: base.c:92
#define FR_DEBUG_STRERROR_PRINTF
Definition: base.c:81
fr_dict_attr_t const * attr_chargeable_user_identity
Definition: base.c:56
ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, uint8_t const *vector, char const *secret)
Simple wrapper for callers who just need a shared secret.
Definition: base.c:1097
static fr_table_num_ordered_t const subtype_table[]
Definition: base.c:1151
void fr_radius_global_free(void)
Definition: base.c:1142
ssize_t fr_radius_encode_dbuff(fr_dbuff_t *dbuff, uint8_t const *original, char const *secret, size_t secret_len, int code, int id, fr_pair_list_t *vps)
Definition: base.c:887
fr_table_num_sorted_t const fr_radius_request_name_table[]
Definition: base.c:83
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition: base.c:94
ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code)
Basic validation of RADIUS packet header.
Definition: base.c:228
int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
Definition: base.c:170
ssize_t fr_radius_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
Definition: decode.c:2087
ssize_t fr_radius_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, fr_radius_decode_ctx_t *packet_ctx)
Create a "normal" fr_pair_t from the given data.
Definition: decode.c:1982
ssize_t fr_radius_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a data structure into a RADIUS attribute.
Definition: encode.c:1498
ssize_t fr_radius_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
Definition: encode.c:1663
VQP attributes.
static rc_request_t * current
Definition: radclient-ng.c:97
static char * secret
Definition: radclient-ng.c:69
@ FLAG_CONCAT
the attribute is concatenated
Definition: radius.h:86
@ FLAG_ENCRYPT_ASCEND_SECRET
Encrypt attribute ascend style.
Definition: radius.h:93
@ FLAG_ENCRYPT_TUNNEL_PASSWORD
Encrypt attribute RFC 2868 style.
Definition: radius.h:92
@ FLAG_ENCRYPT_USER_PASSWORD
Encrypt attribute RFC 2865 style.
Definition: radius.h:91
@ FLAG_TAGGED_TUNNEL_PASSWORD
the attribute has a tag and is encrypted
Definition: radius.h:89
@ FLAG_HAS_TAG
the attribute has a tag
Definition: radius.h:87
@ FLAG_EXTENDED_ATTR
the attribute is an extended attribute
Definition: radius.h:84
@ FLAG_ABINARY
the attribute is in "abinary" format
Definition: radius.h:88
@ FLAG_LONG_EXTENDED_ATTR
the attribute is a long extended attribute
Definition: radius.h:85
fr_fast_rand_t rand_ctx
for tunnel passwords
Definition: radius.h:127
#define flag_has_tag(_flags)
Definition: radius.h:97
uint8_t request_code
original code for the request.
Definition: radius.h:144
uint8_t const * request_authenticator
Definition: radius.h:139
bool disallow_tunnel_passwords
not all packets can have tunnel passwords
Definition: radius.h:132
char const * secret
Definition: radius.h:111
#define flag_extended(_flags)
Definition: radius.h:101
uint8_t const * end
end of the packet
Definition: radius.h:142
uint8_t const * request_authenticator
Definition: radius.h:125
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
vector for authenticating the reply
Definition: radius.h:119
bool require_message_authenticator
Definition: radius.h:148
size_t secret_length
Definition: radius.h:112
@ DECODE_FAIL_INVALID_ATTRIBUTE
Definition: radius.h:66
@ DECODE_FAIL_ATTRIBUTE_UNDERFLOW
Definition: radius.h:70
@ DECODE_FAIL_MIN_LENGTH_FIELD
Definition: radius.h:62
@ DECODE_FAIL_HEADER_OVERFLOW
Definition: radius.h:64
@ DECODE_FAIL_ATTRIBUTE_TOO_SHORT
Definition: radius.h:67
@ DECODE_FAIL_ATTRIBUTE_OVERFLOW
Definition: radius.h:68
@ DECODE_FAIL_TOO_MANY_ATTRIBUTES
Definition: radius.h:71
@ DECODE_FAIL_NONE
Definition: radius.h:60
@ DECODE_FAIL_MIN_LENGTH_PACKET
Definition: radius.h:61
@ DECODE_FAIL_MIN_LENGTH_MISMATCH
Definition: radius.h:63
@ DECODE_FAIL_MA_INVALID_LENGTH
Definition: radius.h:69
@ DECODE_FAIL_MA_MISSING
Definition: radius.h:72
@ DECODE_FAIL_UNKNOWN_PACKET_CODE
Definition: radius.h:65
bool verify
can skip verify for dynamic clients
Definition: radius.h:147
#define flag_concat(_flags)
Definition: radius.h:98
fr_radius_ctx_t * common
Definition: radius.h:123
fr_radius_ctx_t * common
Definition: radius.h:137
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition: radius.h:141
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
uint32_t b
Definition: rand.h:55
uint32_t a
Definition: rand.h:55
static char const * name
fr_assert(0)
fr_aka_sim_id_type_t type
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
An element in an arbitrarily ordered array of name to num mappings.
Definition: table.h:53
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
#define UDP_FLAGS_PEEK
Definition: udp.h:39
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:568
#define PAIR_VERIFY(_x)
Definition: pair.h:190
static fr_slen_t parent
Definition: pair.h:844
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition: proto.h:41
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const_push(_msg)
Definition: strerror.h:227
#define fr_strerror_const(_msg)
Definition: strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
return fr_dbuff_set(dbuff, &our_dbuff)
static size_t char fr_sbuff_t size_t inlen
Definition: value.h:984
static size_t char ** out
Definition: value.h:984