The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
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: 621b20479b2d80c99339773f83cf3cdc5fbcafc6 $
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 */
25RCSID("$Id: 621b20479b2d80c99339773f83cf3cdc5fbcafc6 $")
26
27#include <fcntl.h>
28#include <ctype.h>
29
30#include "attrs.h"
31#include "radius.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
41static bool instantiated = false;
42
45
48 { .out = &dict_freeradius, .proto = "freeradius" },
49 { .out = &dict_radius, .proto = "radius" },
50
52};
53
63
66 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
67 { .out = &attr_packet_authentication_vector, .name = "Packet-Authentication-Vector", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
68 { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
69 { .out = &attr_chargeable_user_identity, .name = "Chargeable-User-Identity", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
70
71 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
72 { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
73 { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
74 { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
75 { .out = &attr_nas_filter_rule, .name = "NAS-Filter-Rule", .type = FR_TYPE_STRING, .dict = &dict_radius },
76
78};
79
80/*
81 * Some messages get printed out only in debugging mode.
82 */
83#define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
84#define FR_DEBUG_STRERROR_PRINTF_PUSH if (fr_debug_lvl) fr_strerror_printf_push
85
94
103
114
116 "", //!< 0
117 "Access-Request",
118 "Access-Accept",
119 "Access-Reject",
120 "Accounting-Request",
121 "Accounting-Response",
122 "Accounting-Status",
123 "Password-Request",
124 "Password-Accept",
125 "Password-Reject",
126 "Accounting-Message", //!< 10
127 "Access-Challenge",
128 "Status-Server",
129 "Status-Client",
130 "14",
131 "15",
132 "16",
133 "17",
134 "18",
135 "19",
136 "20", //!< 20
137 "Resource-Free-Request",
138 "Resource-Free-Response",
139 "Resource-Query-Request",
140 "Resource-Query-Response",
141 "Alternate-Resource-Reclaim-Request",
142 "NAS-Reboot-Request",
143 "NAS-Reboot-Response",
144 "28",
145 "Next-Passcode",
146 "New-Pin", //!< 30
147 "Terminate-Session",
148 "Password-Expired",
149 "Event-Request",
150 "Event-Response",
151 "35",
152 "36",
153 "37",
154 "38",
155 "39",
156 "Disconnect-Request", //!< 40
157 "Disconnect-ACK",
158 "Disconnect-NAK",
159 "CoA-Request",
160 "CoA-ACK",
161 "CoA-NAK",
162 "46",
163 "47",
164 "48",
165 "49",
166 "IP-Address-Allocate", //!< 50
167 "IP-Address-Release",
168 "Protocol-Error",
169};
170
171
172/** If we get a reply, the request must come from one of a small
173 * number of packet types.
174 */
190
193
194static int dict_flag_encrypt(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
195{
196 static fr_table_num_sorted_t const encrypted[] = {
197 { L("Ascend-Secret"), RADIUS_FLAG_ENCRYPT_ASCEND_SECRET },
198 { L("Tunnel-Password"), RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD },
199 { L("User-Password"), RADIUS_FLAG_ENCRYPT_USER_PASSWORD}
200 };
201 static size_t encrypted_len = NUM_ELEMENTS(encrypted);
202
205
207 if (encrypt == RADIUS_FLAG_ENCRYPT_INVALID) {
208 fr_strerror_printf("Unknown encryption type '%s'", value);
209 return -1;
210 }
211
212 flags->encrypt = encrypt;
213
214 return 0;
215}
216
220
222 { L("abinary"), { .func = dict_flag_abinary } },
223 { L("concat"), { .func = dict_flag_concat } },
224 { L("encrypt"), { .func = dict_flag_encrypt, .needs_value = true } },
225 { L("extended"), { .func = dict_flag_extended } },
226 { L("has_tag"), { .func = dict_flag_has_tag } },
227 { L("long_extended"), { .func = dict_flag_long_extended } }
228};
229
230int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
231{
232 int i;
233
234 if ((code <= 0) || (code >= FR_RADIUS_CODE_MAX)) return -1;
235
236 for (i = 1; i < FR_RADIUS_CODE_MAX; i++) {
237 allowed[i] |= (allowed_replies[i] == (fr_radius_packet_code_t) code);
238 }
239
240 return 0;
241}
242
243/** Do Ascend-Send / Recv-Secret calculation.
244 *
245 * The secret is hidden by xoring with a MD5 digest created from
246 * the RADIUS shared secret and the authentication vector.
247 * We put them into MD5 in the reverse order from that used when
248 * encrypting passwords to RADIUS.
249 */
251 char const *secret, size_t secret_len, uint8_t const *vector)
252{
253 fr_md5_ctx_t *md5_ctx;
254 size_t i;
256 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
257
258 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, sizeof(digest));
259
260 md5_ctx = fr_md5_ctx_alloc_from_list();
262 fr_md5_update(md5_ctx, (uint8_t const *) secret, secret_len);
263 fr_md5_final(digest, md5_ctx);
265
266 if (inlen > sizeof(digest)) inlen = sizeof(digest);
267 for (i = 0; i < inlen; i++) digest[i] ^= in[i];
268
269 fr_dbuff_in_memcpy(&work_dbuff, digest, sizeof(digest));
270
271 return fr_dbuff_set(dbuff, &work_dbuff);
272}
273
274/** Basic validation of RADIUS packet header
275 *
276 * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
277 * consumed when discarding malformed packet.
278 *
279 * @param[in] sockfd we're reading from.
280 * @param[out] src_ipaddr of the packet.
281 * @param[out] src_port of the packet.
282 * @param[out] code Pointer to where to write the packet code.
283 * @return
284 * - -1 on failure.
285 * - 1 on decode error.
286 * - >= RADIUS_HEADER_LENGTH on success. This is the packet length as specified in the header.
287 */
288ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code)
289{
290 ssize_t data_len, packet_len;
291 uint8_t header[4];
292
293 data_len = udp_recv_peek(sockfd, header, sizeof(header), UDP_FLAGS_PEEK, src_ipaddr, src_port);
294 if (data_len < 0) {
295 if ((errno == EAGAIN) || (errno == EINTR)) return 0;
296 return -1;
297 }
298
299 /*
300 * Too little data is available, discard the packet.
301 */
302 if (data_len < 4) {
303 char buffer[INET6_ADDRSTRLEN];
304
305 FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zd bytes", data_len);
306invalid:
307 FR_DEBUG_STRERROR_PRINTF_PUSH("Invalid data from %s",
308 inet_ntop(src_ipaddr->af, &src_ipaddr->addr, buffer, sizeof(buffer)));
309 (void) udp_recv_discard(sockfd);
310
311 return 0;
312 }
313
314 /*
315 * See how long the packet says it is.
316 */
317 packet_len = (header[2] * 256) + header[3];
318
319 /*
320 * The length in the packet says it's less than
321 * a RADIUS header length: discard it.
322 */
323 if (packet_len < RADIUS_HEADER_LENGTH) {
324 FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HEADER_LENGTH) " bytes of packet "
325 "data, got %zd bytes", packet_len);
326 goto invalid;
327 }
328
329 /*
330 * Enforce RFC requirements, for sanity.
331 * Anything after 4k will be discarded.
332 */
333 if (packet_len > MAX_PACKET_LEN) {
334 FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
335 STRINGIFY(MAX_PACKET_LEN) " bytes, got %zd bytes", packet_len);
336 goto invalid;
337 }
338
339 *code = header[0];
340
341 /*
342 * The packet says it's this long, but the actual UDP
343 * size could still be smaller.
344 */
345 return packet_len;
346}
347
348/** Sign a previously encoded packet
349 *
350 * Calculates the request/response authenticator for packets which need it, and fills
351 * in the message-authenticator value if the attribute is present in the encoded packet.
352 *
353 * @param[in,out] packet (request or response).
354 * @param[in] vector original packet vector to use
355 * @param[in] secret to sign the packet with.
356 * @param[in] secret_len The length of the secret.
357 * @return
358 * - <0 on error
359 * - 0 on success
360 */
361int fr_radius_sign(uint8_t *packet, uint8_t const *vector,
362 uint8_t const *secret, size_t secret_len)
363{
364 uint8_t *msg, *end;
365 size_t packet_len = fr_nbo_to_uint16(packet + 2);
366
367 /*
368 * No real limit on secret length, this is just
369 * to catch uninitialised fields.
370 */
371 if (!fr_cond_assert(secret_len <= UINT16_MAX)) {
372 fr_strerror_printf("Secret is too long. Expected <= %u, got %zu",
373 (unsigned int) UINT16_MAX, secret_len);
374 return -1;
375 }
376
377 if (packet_len < RADIUS_HEADER_LENGTH) {
378 fr_strerror_const("Packet must be encoded before calling fr_radius_sign()");
379 return -1;
380 }
381
382 /*
383 * Find Message-Authenticator. Its value has to be
384 * calculated before we calculate the Request
385 * Authenticator or the Response Authenticator.
386 */
387 msg = packet + RADIUS_HEADER_LENGTH;
388 end = packet + packet_len;
389
390 while (msg < end) {
391 if ((end - msg) < 2) goto invalid_attribute;
392
393 if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
394 if (msg[1] < 2) goto invalid_attribute;
395
396 if ((msg + msg[1]) > end) {
397 invalid_attribute:
398 fr_strerror_printf("Invalid attribute at offset %zd", msg - packet);
399 return -1;
400 }
401 msg += msg[1];
402 continue;
403 }
404
405 if (msg[1] < 18) {
406 fr_strerror_const("Message-Authenticator is too small");
407 return -1;
408 }
409
410 switch (packet[0]) {
414 memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
415 break;
416
426 if (!vector) goto need_original;
427 memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
428 break;
429
432 /* packet + 4 MUST be the Request Authenticator filled with random data */
433 break;
434
435 default:
436 goto bad_packet;
437 }
438
439 /*
440 * Force Message-Authenticator to be zero,
441 * calculate the HMAC, and put it into the
442 * Message-Authenticator attribute.
443 */
444 memset(msg + 2, 0, RADIUS_AUTH_VECTOR_LENGTH);
445 fr_hmac_md5(msg + 2, packet, packet_len, secret, secret_len);
446 break;
447 }
448
449 /*
450 * Initialize the request authenticator.
451 */
452 switch (packet[0]) {
456 memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
457 break;
458
468 if (!vector) {
469 need_original:
470 fr_strerror_const("Cannot sign response packet without a request packet");
471 return -1;
472 }
473 memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
474 break;
475
476 /*
477 * The Request Authenticator is random numbers.
478 * We don't need to sign anything else, so
479 * return.
480 */
483 return 0;
484
485 default:
486 bad_packet:
487 fr_strerror_printf("Cannot sign unknown packet code %u", packet[0]);
488 return -1;
489 }
490
491 /*
492 * Request / Response Authenticator = MD5(packet + secret)
493 */
494 {
495 fr_md5_ctx_t *md5_ctx;
496
497 md5_ctx = fr_md5_ctx_alloc_from_list();
498 fr_md5_update(md5_ctx, packet, packet_len);
499 fr_md5_update(md5_ctx, secret, secret_len);
500 fr_md5_final(packet + 4, md5_ctx);
502 }
503
504 return 0;
505}
506
508 [FR_RADIUS_FAIL_NONE] = "none",
509 [FR_RADIUS_FAIL_MIN_LENGTH_PACKET] = "packet is smaller than the minimum packet length",
510 [FR_RADIUS_FAIL_MAX_LENGTH_PACKET] = "packet is larger than the maximum packet length",
511 [FR_RADIUS_FAIL_MIN_LENGTH_FIELD] = "header 'length' field has a value smaller than the minimum packet length",
512 [FR_RADIUS_FAIL_MIN_LENGTH_MISMATCH] = "header 'length' field has a value larger than the received data",
513 [FR_RADIUS_FAIL_UNKNOWN_PACKET_CODE] = "unknown packet code",
514 [FR_RADIUS_FAIL_UNEXPECTED_REQUEST_CODE] = "unexpected request code",
515 [FR_RADIUS_FAIL_UNEXPECTED_RESPONSE_CODE] = "unexpected response code",
516 [FR_RADIUS_FAIL_TOO_MANY_ATTRIBUTES] = "packet contains too many attributes",
517
518 [FR_RADIUS_FAIL_INVALID_ATTRIBUTE] = "attribute number 0 is invalid",
519
520 [FR_RADIUS_FAIL_HEADER_OVERFLOW] = "attribute header overflows the packet",
521 [FR_RADIUS_FAIL_ATTRIBUTE_TOO_SHORT] = "attribute 'length' field contains invalid value",
522 [FR_RADIUS_FAIL_ATTRIBUTE_OVERFLOW] = "attribute 'length' field overflows the packet",
523 [FR_RADIUS_FAIL_ATTRIBUTE_DECODE] = "unable to decode attributes",
524
525 [FR_RADIUS_FAIL_MA_INVALID_LENGTH] = "Message-Authenticator has invalid length",
526 [FR_RADIUS_FAIL_MA_MISSING] = "Message-Authenticator is required for this packet, but it is missing",
527 [FR_RADIUS_FAIL_MA_INVALID] = "Message-Authenticator fails verification. shared secret is incorrect",
528 [FR_RADIUS_FAIL_MA_TOO_MANY] = "More than one Message-Authenticator in a packet is invalid",
529 [FR_RADIUS_FAIL_PROXY_STATE_MISSING_MA] = "The packet contains Proxy-State, but no Message-Authenticator",
530
531 [FR_RADIUS_FAIL_VERIFY] = "packet fails verification, shared secret is incorrect",
532 [FR_RADIUS_FAIL_NO_MATCHING_REQUEST] = "did not find request which matched response",
533 [FR_RADIUS_FAIL_IO_ERROR] = "IO error",
534 [FR_RADIUS_FAIL_MAX] = "???",
535};
536
537/** See if the data pointed to by PTR is a valid RADIUS packet.
538 *
539 * @param[in] packet to check.
540 * @param[in,out] packet_len_p The size of the packet data.
541 * @param[in] max_attributes to allow in the packet.
542 * @param[in] require_message_authenticator whether we require Message-Authenticator.
543 * @param[in] reason if not NULL, will have the failure reason written to where it points.
544 * @return
545 * - True on success.
546 * - False on failure.
547 */
548bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p,
549 uint32_t max_attributes, bool require_message_authenticator, fr_radius_decode_fail_t *reason)
550{
551 uint8_t const *attr, *end;
552 size_t totallen;
553 bool seen_ma = false;
554 uint32_t num_attributes;
556 size_t packet_len = *packet_len_p;
557
558 /*
559 * Check for packets smaller than the packet header.
560 *
561 * RFC 2865, Section 3., subsection 'length' says:
562 *
563 * "The minimum length is 20 ..."
564 */
565 if (packet_len < RADIUS_HEADER_LENGTH) {
567 goto finish;
568 }
569
570
571 /*
572 * Check for packets with mismatched size.
573 * i.e. We've received 128 bytes, and the packet header
574 * says it's 256 bytes long.
575 */
576 totallen = fr_nbo_to_uint16(packet + 2);
577
578 /*
579 * Code of 0 is not understood.
580 * Code of 16 or greater is not understood.
581 */
582 if ((packet[0] == 0) ||
583 (packet[0] >= FR_RADIUS_CODE_MAX)) {
585 goto finish;
586 }
587
588 switch (packet[0]) {
589 /*
590 * Message-Authenticator is required in Status-Server
591 * packets, otherwise they can be trivially forged.
592 */
594 require_message_authenticator = true;
595 break;
596
597 /*
598 * Message-Authenticator may or may not be
599 * required for Access-* packets.
600 */
606 break;
607
608 /*
609 * Message-Authenticator is not required for all other packets, but is required if the
610 * caller asks for it.
611 */
614
618
622 break;
623
624 /*
625 * All other packet codes are not handled by the encoder, so we reject them.
626 */
627 default:
629 goto finish;
630 }
631
632 /*
633 * Repeat the length checks. This time, instead of
634 * looking at the data we received, look at the value
635 * of the 'length' field inside of the packet.
636 *
637 * Check for packets smaller than the packet header.
638 *
639 * RFC 2865, Section 3., subsection 'length' says:
640 *
641 * "The minimum length is 20 ..."
642 */
643 if (totallen < RADIUS_HEADER_LENGTH) {
645 goto finish;
646 }
647
648 /*
649 * And again, for the value of the 'length' field.
650 *
651 * RFC 2865, Section 3., subsection 'length' says:
652 *
653 * " ... and maximum length is 4096."
654 *
655 * HOWEVER. This requirement is for the network layer.
656 * If the code gets here, we assume that a well-formed
657 * packet is an OK packet.
658 *
659 * We allow both the UDP data length, and the RADIUS
660 * "length" field to contain up to 64K of data.
661 */
662
663 /*
664 * RFC 2865, Section 3., subsection 'length' says:
665 *
666 * "If the packet is shorter than the Length field
667 * indicates, it MUST be silently discarded."
668 *
669 * i.e. No response to the NAS.
670 */
671 if (totallen > packet_len) {
673 goto finish;
674 }
675
676 /*
677 * RFC 2865, Section 3., subsection 'length' says:
678 *
679 * "Octets outside the range of the Length field MUST be
680 * treated as padding and ignored on reception."
681 */
682 if (totallen < packet_len) {
683 *packet_len_p = packet_len = totallen;
684 }
685
686 /*
687 * Walk through the packet's attributes, ensuring that
688 * they add up EXACTLY to the size of the packet.
689 *
690 * If they don't, then the attributes either under-fill
691 * or over-fill the packet. Any parsing of the packet
692 * is impossible, and will result in unknown side effects.
693 *
694 * This would ONLY happen with buggy RADIUS implementations,
695 * or with an intentional attack. Either way, we do NOT want
696 * to be vulnerable to this problem.
697 */
698 attr = packet + RADIUS_HEADER_LENGTH;
699 end = packet + packet_len;
700 num_attributes = 0;
701
702 while (attr < end) {
703 /*
704 * We need at least 2 bytes to check the
705 * attribute header.
706 */
707 if ((end - attr) < 2) {
709 goto finish;
710 }
711
712 /*
713 * Attribute number zero is NOT defined.
714 */
715 if (attr[0] == 0) {
717 goto finish;
718 }
719
720 /*
721 * Attributes are at LEAST as long as the ID & length
722 * fields. Anything shorter is an invalid attribute.
723 */
724 if (attr[1] < 2) {
726 goto finish;
727 }
728
729 /*
730 * If there are fewer bytes in the packet than in the
731 * attribute, it's a bad packet.
732 */
733 if ((attr + attr[1]) > end) {
735 goto finish;
736 }
737
738 /*
739 * Sanity check the attributes for length.
740 */
741 switch (attr[0]) {
742 default: /* don't do anything by default */
743 break;
744
745 /*
746 * If there's an EAP-Message, we require
747 * a Message-Authenticator.
748 */
749 case FR_EAP_MESSAGE:
750 require_message_authenticator = true;
751 break;
752
753 case FR_MESSAGE_AUTHENTICATOR:
754 if (attr[1] != 2 + RADIUS_AUTH_VECTOR_LENGTH) {
756 goto finish;
757 }
758
759 /*
760 * Can't have two of them.
761 */
762 if (seen_ma) {
764 goto finish;
765 }
766
767 seen_ma = true;
768 break;
769 }
770
771 attr += attr[1];
772 num_attributes++; /* seen one more attribute */
773
774 /*
775 * If we're configured to look for a maximum number of
776 * attributes, and we've seen more than that maximum,
777 * then throw the packet away, as a possible DoS.
778 */
779 if (num_attributes > max_attributes) {
781 goto finish;
782 }
783 }
784
785 /*
786 * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
787 *
788 * A packet with an EAP-Message attribute MUST also have
789 * a Message-Authenticator attribute.
790 *
791 * A Message-Authenticator all by itself is OK, though.
792 *
793 * Similarly, Status-Server packets MUST contain
794 * Message-Authenticator attributes.
795 */
796 if (require_message_authenticator && !seen_ma) {
798 goto finish;
799 }
800
801finish:
802
803 if (reason) *reason = failure;
804
805 return (failure == FR_RADIUS_FAIL_NONE);
806}
807
808
809/** Verify the signature of a request / response packet
810 *
811 * This function does its work by calling fr_radius_sign(), and then comparing the signature in the packet
812 * with the one we calculated. If they differ, there's a problem.
813 *
814 * @note - We rely on the security of the shared secret for UDP and TCP transport. For TLS transport, we
815 * rely on TLS to make the RADIUS packets both secure and private.
816 *
817 * @note - The BlastRADIUS mitigations require that "require_message_authenticator" and "limit_proxy_state"
818 * are used only for Access-Request packets. These mitigations MUST NOT be used for any any other packet
819 * codes.
820 *
821 * The caller should have called fr_radius_packet_ok() to see if the packet is well-formed, at least for the
822 * base RFC attributes.
823 *
824 * @param[in] packet the raw RADIUS packet (request or response)
825 * @param[in] vector the original packet vector
826 * @param[in] secret the shared secret
827 * @param[in] secret_len the length of the secret
828 * @param[in] require_message_authenticator whether we require Message-Authenticator.
829 * @param[in] limit_proxy_state whether we allow Proxy-State without Message-Authenticator.
830 * @return
831 * < <0 on error (negative fr_radius_decode_fail_t)
832 * - 0 on success.
833 */
834int fr_radius_verify(uint8_t *packet, uint8_t const *vector,
835 uint8_t const *secret, size_t secret_len,
836 bool require_message_authenticator, bool limit_proxy_state)
837{
838 bool found_message_authenticator = false;
839 bool found_proxy_state = false;
840 int rcode;
841 int code;
842 uint8_t *attr, *msg, *end;
843 size_t packet_len = fr_nbo_to_uint16(packet + 2);
844 uint8_t request_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
845 uint8_t message_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
846
847 if (packet_len < RADIUS_HEADER_LENGTH) {
848 fr_strerror_printf("invalid packet length %zu", packet_len);
850 }
851
852 code = packet[0];
853 if (!code || (code >= FR_RADIUS_CODE_MAX)) {
854 fr_strerror_printf("Unknown reply code %d", code);
856 }
857
858 /*
859 * RFC 5997 says that all Status-Server packets MUST contain Message-Authenticator.
860 */
861 require_message_authenticator |= (code == FR_RADIUS_CODE_STATUS_SERVER);
862
863 memcpy(request_authenticator, packet + 4, sizeof(request_authenticator));
864
865 /*
866 * Find Message-Authenticator. Its value has to be
867 * calculated before we calculate the Request
868 * Authenticator or the Response Authenticator.
869 */
870 msg = NULL;
871 attr = packet + RADIUS_HEADER_LENGTH;
872 end = packet + packet_len;
873
874 /*
875 * See what we need to do in order to verify the packet.
876 *
877 * Note that fr_radius_packet_ok() also does these checks, but it's worth re-doing them here so
878 * that potential API mis-use is safe. i.e. we do "defense in depth".
879 */
880 while (attr < end) {
881 if ((end - attr) < 2) goto invalid_attribute;
882
883 if (attr[1] < 2) goto invalid_attribute;
884
885 if ((attr + attr[1]) > end) {
886 invalid_attribute:
887 fr_strerror_printf("invalid attribute at offset %zd", attr - packet);
889 }
890
891 /*
892 * If there's no Message-Authenticator, then we need to check Proxy-State, but only if
893 * the caller asked us to limit Proxy-State.
894 */
895 if (attr[0] == FR_PROXY_STATE) {
896 found_proxy_state = limit_proxy_state;
897 goto next;
898 }
899
900 /*
901 * Check the contents of Message-Authenticator
902 */
903 if (attr[0] == FR_MESSAGE_AUTHENTICATOR) {
904 if (found_message_authenticator) {
905 fr_strerror_const("Multiple Message-Authenticators are invalid");
907 }
908
909
910 if (attr[1] != 18) {
911 fr_strerror_const("too small Message-Authenticator");
913 }
914
915 /*
916 * If we have found Message-Authenticator, then we verify that. We also can stop
917 * processing the packet, as we don't care about the contents of Proxy-State.
918 */
919 memcpy(message_authenticator, attr + 2, sizeof(message_authenticator));
920 found_message_authenticator = true;
921 msg = attr;
922 goto next;
923 }
924
925 /*
926 * RFC 3579 Section 3.1 requires Message-Authenticator if the packet contains
927 * EAP-Message.
928 */
929 if (attr[0] == FR_EAP_MESSAGE) require_message_authenticator = true;
930
931 next:
932 attr += attr[1];
933 }
934
935 /*
936 * Enforce limit_proxy_state for Access-Request packets.
937 */
938 if (code == FR_RADIUS_CODE_ACCESS_REQUEST) {
939 if (limit_proxy_state && found_proxy_state && !found_message_authenticator) {
940 fr_strerror_const("Proxy-State is not allowed without Message-Authenticator");
942 }
943 }
944
945 /*
946 * The require_message_authenticator flag can be set for any of these packet types. For other
947 * packet types, we check it if it exists, but we allow packets to not contain it.
948 */
949 if (require_message_authenticator && !found_message_authenticator) {
950 fr_strerror_printf("%s is missing the required Message-Authenticator attribute",
953 }
954
955 /*
956 * Overwrite the contents of Message-Authenticator
957 * with the one we calculate.
958 */
959 rcode = fr_radius_sign(packet, vector, secret, secret_len);
960 if (rcode < 0) {
961 fr_strerror_const_push("Failed calculating correct authenticator");
962 return -FR_RADIUS_FAIL_VERIFY;
963 }
964
965 /*
966 * Check the Message-Authenticator first.
967 *
968 * If it's invalid, restore the original
969 * Message-Authenticator and Request Authenticator
970 * fields.
971 *
972 * If it's valid the original and calculated
973 * message authenticators are the same, so we don't
974 * need to do anything.
975 */
976 if (msg &&
977 (fr_digest_cmp(message_authenticator, msg + 2, sizeof(message_authenticator)) != 0)) {
978 memcpy(msg + 2, message_authenticator, sizeof(message_authenticator));
979 memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
980
981 fr_strerror_const("invalid Message-Authenticator (shared secret is incorrect)");
983 }
984
985 /*
986 * These are random numbers, so there's no point in
987 * comparing them.
988 */
990 return 0;
991 }
992
993 /*
994 * Check the Request Authenticator.
995 */
996 if (fr_digest_cmp(request_authenticator, packet + 4, sizeof(request_authenticator)) != 0) {
997 memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
998 if (vector) {
999 fr_strerror_const("invalid Response Authenticator (shared secret is incorrect)");
1000 } else {
1001 fr_strerror_const("invalid Request Authenticator (shared secret is incorrect)");
1002 }
1003 return -FR_RADIUS_FAIL_VERIFY;
1004 }
1005
1006 return 0;
1007}
1008
1009void *fr_radius_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx);
1010
1011void *fr_radius_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
1012{
1013 fr_pair_t *c = current;
1014 fr_dict_t *dict = talloc_get_type_abort(uctx, fr_dict_t);
1015
1016 while ((c = fr_dlist_next(cursor->dlist, c))) {
1017 PAIR_VERIFY(c);
1018 if ((c->da->dict == dict) &&
1019 (!c->da->flags.internal || ((c->da->attr > FR_TAG_BASE) && (c->da->attr < (FR_TAG_BASE + 0x20))))) {
1020 break;
1021 }
1022 }
1023
1024 return c;
1025}
1026
1027
1029{
1030 ssize_t slen;
1031 fr_pair_t const *vp;
1032 fr_dcursor_t cursor;
1033 fr_dbuff_t work_dbuff, length_dbuff;
1034
1035 /*
1036 * The RADIUS header can't do more than 64K of data.
1037 */
1038 work_dbuff = FR_DBUFF_MAX(dbuff, 65535);
1039
1040 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, packet_ctx->code, packet_ctx->id);
1041 length_dbuff = FR_DBUFF(&work_dbuff);
1043
1044 switch (packet_ctx->code) {
1047 packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
1048
1049 /*
1050 * Allow over-rides of the authentication vector for testing.
1051 */
1053 if (vp && (vp->vp_length >= RADIUS_AUTH_VECTOR_LENGTH)) {
1054 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, RADIUS_AUTH_VECTOR_LENGTH);
1055 } else {
1056 int i;
1057
1058 for (i = 0; i < 4; i++) {
1059 FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t) fr_rand());
1060 }
1061 }
1062 break;
1063
1073 if (!packet_ctx->request_authenticator) {
1074 fr_strerror_const("Cannot encode response without request");
1075 return -1;
1076 }
1078 break;
1079
1082 /*
1083 * Tunnel-Password encoded attributes are allowed
1084 * in CoA-Request packets, by RFC 5176 Section
1085 * 3.6. HOWEVER, the tunnel passwords are
1086 * "encrypted" using the Request Authenticator,
1087 * which is all zeros! That makes them much
1088 * easier to decrypt. The only solution here is
1089 * to say "don't do that!"
1090 */
1092 packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
1093
1095 break;
1096
1097 default:
1098 fr_strerror_printf("Cannot encode unknown packet code %d", packet_ctx->code);
1099 return -1;
1100 }
1101
1102 /*
1103 * Always add Message-Authenticator after the packet
1104 * header for insecure transport protocols.
1105 */
1106 if (!packet_ctx->common->secure_transport) switch (packet_ctx->code) {
1110#ifdef NAS_VIOLATES_RFC
1111 /*
1112 * Allow ridiculous behavior for vendors who violate the RFCs.
1113 *
1114 * But only if there's no EAP-Message in the packet.
1115 */
1116 if (packet_ctx->allow_vulnerable_clients && !fr_pair_find_by_da(vps, NULL, attr_eap_message)) {
1117 break;
1118 }
1120#endif
1121
1125 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_MESSAGE_AUTHENTICATOR, 0x12,
1126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
1128 packet_ctx->seen_message_authenticator = true;
1129 break;
1130
1131 default:
1132 break;
1133 }
1134
1135 /*
1136 * If we're sending Protocol-Error, add in
1137 * Original-Packet-Code manually. If the user adds it
1138 * later themselves, well, too bad.
1139 */
1140 if (packet_ctx->code == FR_RADIUS_CODE_PROTOCOL_ERROR) {
1141 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_EXTENDED_ATTRIBUTE_1, 0x07, 0x04 /* Original-Packet-Code */,
1142 0x00, 0x00, 0x00, packet_ctx->request_code);
1143 }
1144
1145 /*
1146 * Loop over the reply attributes for the packet.
1147 */
1149 while ((vp = fr_dcursor_current(&cursor))) {
1150 PAIR_VERIFY(vp);
1151
1152 /*
1153 * Encode an individual VP
1154 */
1155 slen = fr_radius_encode_pair(&work_dbuff, &cursor, packet_ctx);
1156 if (slen < 0) return slen;
1157 } /* done looping over all attributes */
1158
1159 /*
1160 * Add Proxy-State to the end of the packet if the caller requested it.
1161 */
1162 if (packet_ctx->add_proxy_state) {
1163 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_PROXY_STATE, (uint8_t) (2 + sizeof(packet_ctx->common->proxy_state)));
1164 FR_DBUFF_IN_RETURN(&work_dbuff, packet_ctx->common->proxy_state);
1165 }
1166
1167 /*
1168 * Fill in the length field we zeroed out earlier.
1169 *
1170 */
1171 fr_dbuff_in(&length_dbuff, (uint16_t) (fr_dbuff_used(&work_dbuff)));
1172
1173 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "%s encoded packet", __FUNCTION__);
1174
1175 return fr_dbuff_set(dbuff, &work_dbuff);
1176}
1177
1179 uint8_t *packet, size_t packet_len,
1180 fr_radius_decode_ctx_t *decode_ctx)
1181{
1182 ssize_t slen;
1183 uint8_t const *attr, *end;
1184 static const uint8_t zeros[RADIUS_AUTH_VECTOR_LENGTH] = {};
1185
1186 decode_ctx->reason = FR_RADIUS_FAIL_NONE;
1187
1188 if (!decode_ctx->request_authenticator) {
1189 switch (packet[0]) {
1192 decode_ctx->request_authenticator = packet + 4;
1193 break;
1194
1198 decode_ctx->request_authenticator = zeros;
1199 break;
1200
1201 default:
1202 fr_strerror_const("No authentication vector passed for packet decode");
1204 return -1;
1205 }
1206 }
1207
1208 if (decode_ctx->request_code) {
1209 unsigned int code = packet[0];
1210
1211 if (code >= FR_RADIUS_CODE_MAX) {
1213 return -1;
1214 }
1215 if (decode_ctx->request_code >= FR_RADIUS_CODE_MAX) {
1217 return -1;
1218 }
1219
1220 if (!allowed_replies[code]) {
1222 return -1;
1223 }
1224
1225 /*
1226 * Protocol error can reply to any packet.
1227 *
1228 * Status-Server can get any reply.
1229 *
1230 * Otherwise the reply code must be associated with the request code we sent.
1231 */
1232 if ((allowed_replies[code] != decode_ctx->request_code) &&
1234 (decode_ctx->request_code != FR_RADIUS_CODE_STATUS_SERVER)) {
1236 return -1;
1237 }
1238 }
1239
1240 /*
1241 * We can skip verification for dynamic client checks, and where packets are unsigned as with
1242 * RADIUS/1.1.
1243 */
1244 if (decode_ctx->verify) {
1245 if (!decode_ctx->request_authenticator) decode_ctx->request_authenticator = zeros;
1246
1247 if (fr_radius_verify(packet, decode_ctx->request_authenticator,
1248 (uint8_t const *) decode_ctx->common->secret, decode_ctx->common->secret_length,
1249 decode_ctx->require_message_authenticator, decode_ctx->limit_proxy_state) < 0) {
1250 decode_ctx->reason = FR_RADIUS_FAIL_VERIFY;
1251 return -1;
1252 }
1253 }
1254
1255 attr = packet + 20;
1256 end = packet + packet_len;
1257
1258 /*
1259 * The caller MUST have called fr_radius_ok() first. If
1260 * he doesn't, all hell breaks loose.
1261 */
1262 while (attr < end) {
1263 slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), decode_ctx);
1264 if (slen < 0) {
1266 return slen;
1267 }
1268
1269 /*
1270 * If slen is larger than the room in the packet,
1271 * all kinds of bad things happen.
1272 */
1273 if (!fr_cond_assert(slen <= (end - attr))) {
1274 return -slen;
1275 }
1276
1277 attr += slen;
1278 talloc_free_children(decode_ctx->tmp_ctx);
1279 }
1280
1281 /*
1282 * We've parsed the whole packet, return that.
1283 */
1284 return packet_len;
1285}
1286
1287/** Simple wrapper for callers who just need a shared secret
1288 *
1289 * @note - All callers verify the packet via fr_radius_packet_verify() before calling this function.
1290 */
1292 uint8_t *packet, size_t packet_len,
1293 uint8_t const *vector, char const *secret)
1294{
1295 ssize_t rcode;
1296 fr_radius_ctx_t common_ctx = {};
1297 fr_radius_decode_ctx_t packet_ctx = {};
1298
1299 common_ctx.secret = secret;
1300 common_ctx.secret_length = strlen(secret);
1301
1302 packet_ctx.common = &common_ctx;
1303 packet_ctx.tmp_ctx = talloc(ctx, uint8_t);
1304 packet_ctx.request_authenticator = vector;
1305 packet_ctx.end = packet + packet_len;
1306
1307 rcode = fr_radius_decode(ctx, out, packet, packet_len, &packet_ctx);
1308 talloc_free(packet_ctx.tmp_ctx);
1309
1310 return rcode;
1311}
1312
1314{
1315 if (instance_count > 0) {
1317 return 0;
1318 }
1319
1321
1323 fail:
1325 return -1;
1326 }
1327
1330 goto fail;
1331 }
1332
1333 instantiated = true;
1334 return 0;
1335}
1336
1338{
1339 if (!instantiated) return;
1340
1341 if (--instance_count != 0) return;
1342
1344
1345 instantiated = false;
1346}
1347
1349{
1351
1352 if (da->parent->type == FR_TYPE_STRUCT) {
1353 if (flags->extended) {
1354 fr_strerror_const("Attributes with 'extended' flag cannot be used inside of a 'struct'");
1355 return false;
1356 }
1357
1358 if (flags->long_extended) {
1359 fr_strerror_const("Attributes with 'long_extended' flag cannot be used inside of a 'struct'");
1360 return false;
1361 }
1362
1363
1364 if (flags->concat) {
1365 fr_strerror_const("Attributes with 'concat' flag cannot be used inside of a 'struct'");
1366 return false;
1367 }
1368
1369 if (flags->has_tag) {
1370 fr_strerror_const("Attributes with 'tag' flag cannot be used inside of a 'struct'");
1371 return false;
1372 }
1373
1374 if (flags->abinary) {
1375 fr_strerror_const("Attributes with 'abinary' flag cannot be used inside of a 'struct'");
1376 return false;
1377 }
1378
1379 if (flags->encrypt > 0) {
1380 fr_strerror_const("Attributes with 'encrypt' flag cannot be used inside of a 'struct'");
1381 return false;
1382 }
1383
1384 return true;
1385 }
1386
1387 if (da->flags.length > 253) {
1388 fr_strerror_printf("Attributes cannot be more than 253 octets in length");
1389 return false;
1390 }
1391 /*
1392 * Secret things are secret.
1393 */
1394 if (flags->encrypt != 0) da->flags.secret = true;
1395
1396 if (flags->concat) {
1397 if (!da->parent->flags.is_root) {
1398 fr_strerror_const("Attributes with the 'concat' flag MUST be at the root of the dictionary");
1399 return false;
1400 }
1401
1402 if (da->type != FR_TYPE_OCTETS) {
1403 fr_strerror_const("Attributes with the 'concat' flag MUST be of data type 'octets'");
1404 return false;
1405 }
1406
1407 return true; /* can't use any other flag */
1408 }
1409
1410 /*
1411 * Tagged attributes can only be of two data types. They
1412 * can, however, be VSAs.
1413 */
1414 if (flags->has_tag) {
1415 if ((da->type != FR_TYPE_UINT32) && (da->type != FR_TYPE_STRING)) {
1416 fr_strerror_printf("The 'has_tag' flag can only be used for attributes of type 'integer' "
1417 "or 'string'");
1418 return false;
1419 }
1420
1421 if (!(da->parent->flags.is_root ||
1422 ((da->parent->type == FR_TYPE_VENDOR) &&
1423 (da->parent->parent && da->parent->parent->type == FR_TYPE_VSA)))) {
1424 fr_strerror_const("The 'has_tag' flag can only be used with RFC and VSA attributes");
1425 return false;
1426 }
1427
1428 return true;
1429 }
1430
1431 if (flags->extended) {
1432 if (da->type != FR_TYPE_TLV) {
1433 fr_strerror_const("The 'long' or 'extended' flag can only be used for attributes of type 'tlv'");
1434 return false;
1435 }
1436
1437 if (!da->parent->flags.is_root) {
1438 fr_strerror_const("The 'long' flag can only be used for top-level RFC attributes");
1439 return false;
1440 }
1441
1442 return true;
1443 }
1444
1445 /*
1446 * Stupid hacks for MS-CHAP-MPPE-Keys. The User-Password
1447 * encryption method has no provisions for encoding the
1448 * length of the data. For User-Password, the data is
1449 * (presumably) all printable non-zero data. For
1450 * MS-CHAP-MPPE-Keys, the data is binary crap. So... we
1451 * MUST specify a length in the dictionary.
1452 */
1453 if ((flags->encrypt == RADIUS_FLAG_ENCRYPT_USER_PASSWORD) && (da->type != FR_TYPE_STRING)) {
1454 if (da->type != FR_TYPE_OCTETS) {
1455 fr_strerror_printf("The 'encrypt=User-Password' flag can only be used with "
1456 "attributes of type 'string'");
1457 return false;
1458 }
1459
1460 if (da->flags.length == 0) {
1461 fr_strerror_printf("The 'encrypt=User-Password' flag MUST be used with an explicit length for "
1462 "'octets' data types");
1463 return false;
1464 }
1465 }
1466
1467 switch (da->type) {
1468 case FR_TYPE_STRING:
1469 break;
1470
1471 case FR_TYPE_TLV:
1472 case FR_TYPE_IPV4_ADDR:
1473 case FR_TYPE_UINT32:
1474 case FR_TYPE_OCTETS:
1475 if (flags->encrypt != RADIUS_FLAG_ENCRYPT_ASCEND_SECRET) break;
1477
1478 default:
1479 if (flags->encrypt) {
1480 fr_strerror_printf("The 'encrypt' flag cannot be used with attributes of type '%s'",
1481 fr_type_to_str(da->type));
1482 return false;
1483 }
1484 }
1485
1486 return true;
1487}
1488
1491 .name = "radius",
1492 .default_type_size = 1,
1493 .default_type_length = 1,
1494 .attr = {
1495 .flags = {
1496 .table = radius_flags,
1497 .table_len = NUM_ELEMENTS(radius_flags),
1498 .len = sizeof(fr_radius_attr_flags_t),
1499 },
1500 .valid = attr_valid,
1501 },
1502
1503 .init = fr_radius_global_init,
1504 .free = fr_radius_global_free,
1505
1506 .decode = fr_radius_decode_foreign,
1507 .encode = fr_radius_encode_foreign,
1508};
static int const char char buffer[256]
Definition acutest.h:576
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:512
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define STRINGIFY(x)
Definition build.h:216
#define UNUSED
Definition build.h:336
#define NUM_ELEMENTS(_t)
Definition build.h:358
fr_dict_t * dict
Definition common.c:31
#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:775
#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:681
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:919
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1012
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:906
#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:1517
#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:1391
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1359
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition dbuff.h:1576
#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:1594
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:230
#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:309
#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:1481
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:337
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
Definition dcursor.h:92
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
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:55
#define fr_dict_autofree(_to_free)
Definition dict.h:915
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
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:4372
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:190
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
static fr_slen_t in
Definition dict.h:882
char const * name
name of this protocol
Definition dict.h:456
#define FR_DICT_ATTR_FLAG_FUNC(_struct, _name)
Define a flag setting function, which sets one bit in a fr_dict_attr_flags_t.
Definition dict.h:435
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
Protocol specific custom flag definitnion.
Definition dict.h:425
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:455
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:121
Test enumeration values.
Definition dict_test.h:92
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:537
talloc_free(hp)
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:63
union fr_ipaddr_t::@137 addr
IPv4/6 prefix.
static fr_dict_t const * dict_freeradius
Definition base.c:37
fr_dict_attr_t const * attr_packet_type
Definition base.c:91
fr_dict_attr_t const * attr_eap_message
Definition base.c:94
fr_dict_t const * dict_radius
Definition base.c:76
fr_dict_attr_t const * attr_message_authenticator
Definition base.c:92
static int dict_flag_encrypt(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:227
static uint32_t instance_count
Definition base.c:44
int udp_recv_discard(int sockfd)
Discard the next UDP packet.
Definition udp.c:75
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:95
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Free function for MD5 digest ctx.
Definition md5.c:515
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Allocation function for MD5 digest context.
Definition md5.c:470
#define fr_md5_final(_out, _ctx)
Finalise the ctx, producing the digest.
Definition md5.h:90
void fr_md5_ctx_t
Definition md5.h:25
#define fr_md5_update(_ctx, _in, _inlen)
Ingest plaintext into the digest.
Definition md5.h:83
#define MD5_DIGEST_LENGTH
unsigned short uint16_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
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:504
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition missing.c:447
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:146
#define RADIUS_HEADER_LENGTH
Definition net.h:80
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
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:707
static fr_dict_attr_t const * attr_state
Definition base.c:58
static uint8_t const zeros[6]
Definition base.c:105
static bool instantiated
Definition base.c:39
static bool attr_valid(fr_dict_attr_t *da)
Definition base.c:484
fr_dict_protocol_t libfreeradius_radius_dict_protocol
Definition base.c:1490
fr_dict_autoload_t libfreeradius_radius_dict[]
Definition base.c:47
ssize_t fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen, char const *secret, size_t secret_len, uint8_t const *vector)
Do Ascend-Send / Recv-Secret calculation.
Definition base.c:250
fr_dict_attr_t const * attr_nas_filter_rule
Definition base.c:62
static fr_dict_flag_parser_t const radius_flags[]
Definition base.c:221
fr_dict_attr_t const * attr_packet_authentication_vector
Definition base.c:55
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:175
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:1178
size_t fr_radius_limit_proxy_state_table_len
Definition base.c:102
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:361
int fr_radius_verify(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len, bool require_message_authenticator, bool limit_proxy_state)
Verify the signature of a request / response packet.
Definition base.c:834
fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[]
Definition base.c:65
char const * fr_radius_decode_fail_reason[FR_RADIUS_FAIL_MAX+1]
Definition base.c:507
size_t fr_radius_require_ma_table_len
Definition base.c:93
fr_dict_attr_t const * attr_chap_challenge
Definition base.c:56
void * fr_radius_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
Definition base.c:1011
fr_dict_attr_t const * attr_vendor_specific
Definition base.c:61
int fr_radius_global_init(void)
Definition base.c:1313
size_t fr_radius_request_name_table_len
Definition base.c:113
#define FR_DEBUG_STRERROR_PRINTF
Definition base.c:83
fr_dict_attr_t const * attr_chargeable_user_identity
Definition base.c:57
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:1291
void fr_radius_global_free(void)
Definition base.c:1337
fr_table_num_sorted_t const fr_radius_limit_proxy_state_table[]
Definition base.c:95
fr_table_num_sorted_t const fr_radius_request_name_table[]
Definition base.c:104
fr_table_num_sorted_t const fr_radius_require_ma_table[]
Definition base.c:86
bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p, uint32_t max_attributes, bool require_message_authenticator, fr_radius_decode_fail_t *reason)
See if the data pointed to by PTR is a valid RADIUS packet.
Definition base.c:548
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
Definition base.c:1028
#define FR_DEBUG_STRERROR_PRINTF_PUSH
Definition base.c:84
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:115
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:288
int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
Definition base.c:230
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:2099
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:1979
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:1551
ssize_t fr_radius_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
Definition encode.c:1724
VQP attributes.
static char * secret
unsigned int has_tag
Attribute has a tag.
Definition radius.h:192
bool secure_transport
for TLS
Definition radius.h:130
@ FR_RADIUS_REQUIRE_MA_NO
Do not require Message-Authenticator.
Definition radius.h:62
@ FR_RADIUS_REQUIRE_MA_YES
Require Message-Authenticator.
Definition radius.h:63
@ FR_RADIUS_REQUIRE_MA_AUTO
Only require Message-Authenticator if we've previously received a packet from this client with Messag...
Definition radius.h:64
fr_radius_ctx_t const * common
Definition radius.h:136
uint8_t request_code
original code for the request.
Definition radius.h:168
uint8_t const * request_authenticator
Definition radius.h:161
unsigned int abinary
Attribute is in "abinary" format.
Definition radius.h:193
fr_radius_decode_fail_t
Failure reasons.
Definition radius.h:89
@ FR_RADIUS_FAIL_ATTRIBUTE_DECODE
Definition radius.h:105
@ FR_RADIUS_FAIL_UNEXPECTED_REQUEST_CODE
Definition radius.h:96
@ FR_RADIUS_FAIL_ATTRIBUTE_OVERFLOW
Definition radius.h:104
@ FR_RADIUS_FAIL_VERIFY
Definition radius.h:113
@ FR_RADIUS_FAIL_NONE
Definition radius.h:90
@ FR_RADIUS_FAIL_MA_INVALID_LENGTH
Definition radius.h:107
@ FR_RADIUS_FAIL_MIN_LENGTH_FIELD
Definition radius.h:93
@ FR_RADIUS_FAIL_INVALID_ATTRIBUTE
Definition radius.h:100
@ FR_RADIUS_FAIL_IO_ERROR
Definition radius.h:115
@ FR_RADIUS_FAIL_MAX_LENGTH_PACKET
Definition radius.h:92
@ FR_RADIUS_FAIL_MA_MISSING
Definition radius.h:108
@ FR_RADIUS_FAIL_TOO_MANY_ATTRIBUTES
Definition radius.h:98
@ FR_RADIUS_FAIL_UNEXPECTED_RESPONSE_CODE
Definition radius.h:97
@ FR_RADIUS_FAIL_UNKNOWN_PACKET_CODE
Definition radius.h:95
@ FR_RADIUS_FAIL_MIN_LENGTH_MISMATCH
Definition radius.h:94
@ FR_RADIUS_FAIL_NO_MATCHING_REQUEST
Definition radius.h:114
@ FR_RADIUS_FAIL_HEADER_OVERFLOW
Definition radius.h:102
@ FR_RADIUS_FAIL_MIN_LENGTH_PACKET
Definition radius.h:91
@ FR_RADIUS_FAIL_MAX
Definition radius.h:116
@ FR_RADIUS_FAIL_ATTRIBUTE_TOO_SHORT
Definition radius.h:103
@ FR_RADIUS_FAIL_MA_INVALID
Definition radius.h:109
@ FR_RADIUS_FAIL_PROXY_STATE_MISSING_MA
Definition radius.h:111
@ FR_RADIUS_FAIL_MA_TOO_MANY
Definition radius.h:110
char const * secret
Definition radius.h:127
unsigned int concat
Attribute is concatenated.
Definition radius.h:191
uint8_t const * end
end of the packet
Definition radius.h:164
bool limit_proxy_state
Don't allow Proxy-State in requests.
Definition radius.h:173
uint64_t proxy_state
Definition radius.h:132
uint8_t const * request_authenticator
Definition radius.h:138
unsigned int extended
Attribute is an extended attribute.
Definition radius.h:190
fr_radius_attr_flags_encrypt_t encrypt
Attribute is encrypted.
Definition radius.h:194
bool require_message_authenticator
Definition radius.h:172
size_t secret_length
Definition radius.h:128
bool verify
can skip verify for dynamic clients
Definition radius.h:171
fr_radius_ctx_t const * common
Definition radius.h:159
@ FR_RADIUS_LIMIT_PROXY_STATE_NO
Do not limit Proxy-State.
Definition radius.h:76
@ FR_RADIUS_LIMIT_PROXY_STATE_AUTO
Do not allow Proxy-State unless:
Definition radius.h:81
@ FR_RADIUS_LIMIT_PROXY_STATE_YES
Limit Proxy-State.
Definition radius.h:78
unsigned int long_extended
Attribute is a long extended attribute.
Definition radius.h:189
fr_radius_decode_fail_t reason
reason for decode failure
Definition radius.h:166
fr_radius_attr_flags_encrypt_t
Definition radius.h:180
@ RADIUS_FLAG_ENCRYPT_INVALID
Invalid encryption flag.
Definition radius.h:181
@ RADIUS_FLAG_ENCRYPT_USER_PASSWORD
Encrypt attribute RFC 2865 style.
Definition radius.h:183
@ RADIUS_FLAG_ENCRYPT_ASCEND_SECRET
Encrypt attribute ascend style.
Definition radius.h:185
@ RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD
Encrypt attribute RFC 2868 style.
Definition radius.h:184
static fr_radius_attr_flags_t const * fr_radius_attr_flags(fr_dict_attr_t const *da)
Return RADIUS-specific flags for a given attribute.
Definition radius.h:200
bool add_proxy_state
do we add a Proxy-State?
Definition radius.h:149
bool seen_message_authenticator
Definition radius.h:150
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition radius.h:163
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
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_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#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:584
#define PAIR_VERIFY(_x)
Definition pair.h:204
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#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:454
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1030
static size_t char ** out
Definition value.h:1030