The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: b07964d38eae4944aeabd33fc85cacca9ffac3df $
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: b07964d38eae4944aeabd33fc85cacca9ffac3df $")
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/table.h>
38#include <freeradius-devel/util/udp.h>
39#include <freeradius-devel/protocol/radius/freeradius.internal.h>
40
42
45
48 { .out = &dict_freeradius, .proto = "freeradius" },
49 { .out = &dict_radius, .proto = "radius" },
50 { NULL }
51};
52
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
91
100
111
113 "", //!< 0
114 "Access-Request",
115 "Access-Accept",
116 "Access-Reject",
117 "Accounting-Request",
118 "Accounting-Response",
119 "Accounting-Status",
120 "Password-Request",
121 "Password-Accept",
122 "Password-Reject",
123 "Accounting-Message", //!< 10
124 "Access-Challenge",
125 "Status-Server",
126 "Status-Client",
127 "14",
128 "15",
129 "16",
130 "17",
131 "18",
132 "19",
133 "20", //!< 20
134 "Resource-Free-Request",
135 "Resource-Free-Response",
136 "Resource-Query-Request",
137 "Resource-Query-Response",
138 "Alternate-Resource-Reclaim-Request",
139 "NAS-Reboot-Request",
140 "NAS-Reboot-Response",
141 "28",
142 "Next-Passcode",
143 "New-Pin", //!< 30
144 "Terminate-Session",
145 "Password-Expired",
146 "Event-Request",
147 "Event-Response",
148 "35",
149 "36",
150 "37",
151 "38",
152 "39",
153 "Disconnect-Request", //!< 40
154 "Disconnect-ACK",
155 "Disconnect-NAK",
156 "CoA-Request",
157 "CoA-ACK",
158 "CoA-NAK",
159 "46",
160 "47",
161 "48",
162 "49",
163 "IP-Address-Allocate", //!< 50
164 "IP-Address-Release",
165 "Protocol-Error",
166};
167
168
169/** If we get a reply, the request must come from one of a small
170 * number of packet types.
171 */
187
190
191static int dict_flag_encrypt(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
192{
193 static fr_table_num_sorted_t const encrypted[] = {
194 { L("Ascend-Secret"), RADIUS_FLAG_ENCRYPT_ASCEND_SECRET },
195 { L("Tunnel-Password"), RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD },
196 { L("User-Password"), RADIUS_FLAG_ENCRYPT_USER_PASSWORD}
197 };
198 static size_t encrypted_len = NUM_ELEMENTS(encrypted);
199
202
204 if (encrypt == RADIUS_FLAG_ENCRYPT_INVALID) {
205 fr_strerror_printf("Unknown encryption type '%s'", value);
206 return -1;
207 }
208
209 flags->encrypt = encrypt;
210
211 return 0;
212}
213
217
219 { L("abinary"), { .func = dict_flag_abinary } },
220 { L("concat"), { .func = dict_flag_concat } },
221 { L("encrypt"), { .func = dict_flag_encrypt, .needs_value = true } },
222 { L("extended"), { .func = dict_flag_extended } },
223 { L("has_tag"), { .func = dict_flag_has_tag } },
224 { L("long_extended"), { .func = dict_flag_long_extended } }
225};
226
227int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
228{
229 int i;
230
231 if ((code <= 0) || (code >= FR_RADIUS_CODE_MAX)) return -1;
232
233 for (i = 1; i < FR_RADIUS_CODE_MAX; i++) {
234 allowed[i] |= (allowed_replies[i] == (fr_radius_packet_code_t) code);
235 }
236
237 return 0;
238}
239
240/** Do Ascend-Send / Recv-Secret calculation.
241 *
242 * The secret is hidden by xoring with a MD5 digest created from
243 * the RADIUS shared secret and the authentication vector.
244 * We put them into MD5 in the reverse order from that used when
245 * encrypting passwords to RADIUS.
246 */
248 char const *secret, uint8_t const *vector)
249{
250 fr_md5_ctx_t *md5_ctx;
251 size_t i;
253 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
254
255 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, sizeof(digest));
256
257 md5_ctx = fr_md5_ctx_alloc_from_list();
259 fr_md5_update(md5_ctx, (uint8_t const *) secret, talloc_array_length(secret) - 1);
260 fr_md5_final(digest, md5_ctx);
262
263 if (inlen > sizeof(digest)) inlen = sizeof(digest);
264 for (i = 0; i < inlen; i++) digest[i] ^= in[i];
265
266 fr_dbuff_in_memcpy(&work_dbuff, digest, sizeof(digest));
267
268 return fr_dbuff_set(dbuff, &work_dbuff);
269}
270
271/** Basic validation of RADIUS packet header
272 *
273 * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
274 * consumed when discarding malformed packet.
275 *
276 * @param[in] sockfd we're reading from.
277 * @param[out] src_ipaddr of the packet.
278 * @param[out] src_port of the packet.
279 * @param[out] code Pointer to where to write the packet code.
280 * @return
281 * - -1 on failure.
282 * - 1 on decode error.
283 * - >= RADIUS_HEADER_LENGTH on success. This is the packet length as specified in the header.
284 */
285ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code)
286{
287 ssize_t data_len, packet_len;
288 uint8_t header[4];
289
290 data_len = udp_recv_peek(sockfd, header, sizeof(header), UDP_FLAGS_PEEK, src_ipaddr, src_port);
291 if (data_len < 0) {
292 if ((errno == EAGAIN) || (errno == EINTR)) return 0;
293 return -1;
294 }
295
296 /*
297 * Too little data is available, discard the packet.
298 */
299 if (data_len < 4) {
300 char buffer[INET6_ADDRSTRLEN];
301
302 FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zd bytes", data_len);
303invalid:
304 FR_DEBUG_STRERROR_PRINTF("Invalid data from %s",
305 inet_ntop(src_ipaddr->af, &src_ipaddr->addr, buffer, sizeof(buffer)));
306 (void) udp_recv_discard(sockfd);
307
308 return 0;
309 }
310
311 /*
312 * See how long the packet says it is.
313 */
314 packet_len = (header[2] * 256) + header[3];
315
316 /*
317 * The length in the packet says it's less than
318 * a RADIUS header length: discard it.
319 */
320 if (packet_len < RADIUS_HEADER_LENGTH) {
321 FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HEADER_LENGTH) " bytes of packet "
322 "data, got %zd bytes", packet_len);
323 goto invalid;
324 }
325
326 /*
327 * Enforce RFC requirements, for sanity.
328 * Anything after 4k will be discarded.
329 */
330 if (packet_len > MAX_PACKET_LEN) {
331 FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
332 STRINGIFY(MAX_PACKET_LEN) " bytes, got %zd bytes", packet_len);
333 goto invalid;
334 }
335
336 *code = header[0];
337
338 /*
339 * The packet says it's this long, but the actual UDP
340 * size could still be smaller.
341 */
342 return packet_len;
343}
344
345/** Sign a previously encoded packet
346 *
347 * Calculates the request/response authenticator for packets which need it, and fills
348 * in the message-authenticator value if the attribute is present in the encoded packet.
349 *
350 * @param[in,out] packet (request or response).
351 * @param[in] vector original packet vector to use
352 * @param[in] secret to sign the packet with.
353 * @param[in] secret_len The length of the secret.
354 * @return
355 * - <0 on error
356 * - 0 on success
357 */
358int fr_radius_sign(uint8_t *packet, uint8_t const *vector,
359 uint8_t const *secret, size_t secret_len)
360{
361 uint8_t *msg, *end;
362 size_t packet_len = fr_nbo_to_uint16(packet + 2);
363
364 /*
365 * No real limit on secret length, this is just
366 * to catch uninitialised fields.
367 */
368 if (!fr_cond_assert(secret_len <= UINT16_MAX)) {
369 fr_strerror_printf("Secret is too long. Expected <= %u, got %zu",
370 (unsigned int) UINT16_MAX, secret_len);
371 return -1;
372 }
373
374 if (packet_len < RADIUS_HEADER_LENGTH) {
375 fr_strerror_const("Packet must be encoded before calling fr_radius_sign()");
376 return -1;
377 }
378
379 /*
380 * Find Message-Authenticator. Its value has to be
381 * calculated before we calculate the Request
382 * Authenticator or the Response Authenticator.
383 */
384 msg = packet + RADIUS_HEADER_LENGTH;
385 end = packet + packet_len;
386
387 while (msg < end) {
388 if ((end - msg) < 2) goto invalid_attribute;
389
390 if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
391 if (msg[1] < 2) goto invalid_attribute;
392
393 if ((msg + msg[1]) > end) {
394 invalid_attribute:
395 fr_strerror_printf("Invalid attribute at offset %zd", msg - packet);
396 return -1;
397 }
398 msg += msg[1];
399 continue;
400 }
401
402 if (msg[1] < 18) {
403 fr_strerror_const("Message-Authenticator is too small");
404 return -1;
405 }
406
407 switch (packet[0]) {
411 memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
412 break;
413
422 if (!vector) goto need_original;
423 memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
424 break;
425
428 /* packet + 4 MUST be the Request Authenticator filled with random data */
429 break;
430
431 default:
432 goto bad_packet;
433 }
434
435 /*
436 * Force Message-Authenticator to be zero,
437 * calculate the HMAC, and put it into the
438 * Message-Authenticator attribute.
439 */
440 memset(msg + 2, 0, RADIUS_AUTH_VECTOR_LENGTH);
441 fr_hmac_md5(msg + 2, packet, packet_len, secret, secret_len);
442 break;
443 }
444
445 /*
446 * Initialize the request authenticator.
447 */
448 switch (packet[0]) {
452 memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
453 break;
454
464 if (!vector) {
465 need_original:
466 fr_strerror_const("Cannot sign response packet without a request packet");
467 return -1;
468 }
469 memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
470 break;
471
472 /*
473 * The Request Authenticator is random numbers.
474 * We don't need to sign anything else, so
475 * return.
476 */
479 return 0;
480
481 default:
482 bad_packet:
483 fr_strerror_printf("Cannot sign unknown packet code %u", packet[0]);
484 return -1;
485 }
486
487 /*
488 * Request / Response Authenticator = MD5(packet + secret)
489 */
490 {
491 fr_md5_ctx_t *md5_ctx;
492
493 md5_ctx = fr_md5_ctx_alloc_from_list();
494 fr_md5_update(md5_ctx, packet, packet_len);
495 fr_md5_update(md5_ctx, secret, secret_len);
496 fr_md5_final(packet + 4, md5_ctx);
498 }
499
500 return 0;
501}
502
503
504/** See if the data pointed to by PTR is a valid RADIUS packet.
505 *
506 * @param[in] packet to check.
507 * @param[in,out] packet_len_p The size of the packet data.
508 * @param[in] max_attributes to allow in the packet.
509 * @param[in] require_message_authenticator whether we require Message-Authenticator.
510 * @param[in] reason if not NULL, will have the failure reason written to where it points.
511 * @return
512 * - True on success.
513 * - False on failure.
514 */
515bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p,
516 uint32_t max_attributes, bool require_message_authenticator, fr_radius_decode_fail_t *reason)
517{
518 uint8_t const *attr, *end;
519 size_t totallen;
520 bool seen_ma = false;
521 uint32_t num_attributes;
523 size_t packet_len = *packet_len_p;
524
525 /*
526 * Check for packets smaller than the packet header.
527 *
528 * RFC 2865, Section 3., subsection 'length' says:
529 *
530 * "The minimum length is 20 ..."
531 */
532 if (packet_len < RADIUS_HEADER_LENGTH) {
533 FR_DEBUG_STRERROR_PRINTF("packet is too short (received %zu < minimum 20)",
534 packet_len);
536 goto finish;
537 }
538
539
540 /*
541 * Check for packets with mismatched size.
542 * i.e. We've received 128 bytes, and the packet header
543 * says it's 256 bytes long.
544 */
545 totallen = fr_nbo_to_uint16(packet + 2);
546
547 /*
548 * Code of 0 is not understood.
549 * Code of 16 or greater is not understood.
550 */
551 if ((packet[0] == 0) ||
552 (packet[0] >= FR_RADIUS_CODE_MAX)) {
553 FR_DEBUG_STRERROR_PRINTF("unknown packet code %d", packet[0]);
555 goto finish;
556 }
557
558 /*
559 * Message-Authenticator is required in Status-Server
560 * packets, otherwise they can be trivially forged.
561 */
562 if (packet[0] == FR_RADIUS_CODE_STATUS_SERVER) require_message_authenticator = true;
563
564 /*
565 * Repeat the length checks. This time, instead of
566 * looking at the data we received, look at the value
567 * of the 'length' field inside of the packet.
568 *
569 * Check for packets smaller than the packet header.
570 *
571 * RFC 2865, Section 3., subsection 'length' says:
572 *
573 * "The minimum length is 20 ..."
574 */
575 if (totallen < RADIUS_HEADER_LENGTH) {
576 FR_DEBUG_STRERROR_PRINTF("length in header is too small (length %zu < minimum 20)",
577 totallen);
579 goto finish;
580 }
581
582 /*
583 * And again, for the value of the 'length' field.
584 *
585 * RFC 2865, Section 3., subsection 'length' says:
586 *
587 * " ... and maximum length is 4096."
588 *
589 * HOWEVER. This requirement is for the network layer.
590 * If the code gets here, we assume that a well-formed
591 * packet is an OK packet.
592 *
593 * We allow both the UDP data length, and the RADIUS
594 * "length" field to contain up to 64K of data.
595 */
596
597 /*
598 * RFC 2865, Section 3., subsection 'length' says:
599 *
600 * "If the packet is shorter than the Length field
601 * indicates, it MUST be silently discarded."
602 *
603 * i.e. No response to the NAS.
604 */
605 if (totallen > packet_len) {
606 FR_DEBUG_STRERROR_PRINTF("packet is truncated (received %zu < packet header length of %zu)",
607 packet_len, totallen);
609 goto finish;
610 }
611
612 /*
613 * RFC 2865, Section 3., subsection 'length' says:
614 *
615 * "Octets outside the range of the Length field MUST be
616 * treated as padding and ignored on reception."
617 */
618 if (totallen < packet_len) {
619 *packet_len_p = packet_len = totallen;
620 }
621
622 /*
623 * Walk through the packet's attributes, ensuring that
624 * they add up EXACTLY to the size of the packet.
625 *
626 * If they don't, then the attributes either under-fill
627 * or over-fill the packet. Any parsing of the packet
628 * is impossible, and will result in unknown side effects.
629 *
630 * This would ONLY happen with buggy RADIUS implementations,
631 * or with an intentional attack. Either way, we do NOT want
632 * to be vulnerable to this problem.
633 */
634 attr = packet + RADIUS_HEADER_LENGTH;
635 end = packet + packet_len;
636 num_attributes = 0;
637
638 while (attr < end) {
639 /*
640 * We need at least 2 bytes to check the
641 * attribute header.
642 */
643 if ((end - attr) < 2) {
644 FR_DEBUG_STRERROR_PRINTF("attribute header overflows the packet");
646 goto finish;
647 }
648
649 /*
650 * Attribute number zero is NOT defined.
651 */
652 if (attr[0] == 0) {
653 FR_DEBUG_STRERROR_PRINTF("invalid attribute 0 at offset %zd", attr - packet);
655 goto finish;
656 }
657
658 /*
659 * Attributes are at LEAST as long as the ID & length
660 * fields. Anything shorter is an invalid attribute.
661 */
662 if (attr[1] < 2) {
663 FR_DEBUG_STRERROR_PRINTF("attribute %u is too short at offset %zd",
664 attr[0], attr - packet);
666 goto finish;
667 }
668
669 /*
670 * If there are fewer bytes in the packet than in the
671 * attribute, it's a bad packet.
672 */
673 if ((attr + attr[1]) > end) {
674 FR_DEBUG_STRERROR_PRINTF("attribute %u data overflows the packet starting at offset %zd",
675 attr[0], attr - packet);
677 goto finish;
678 }
679
680 /*
681 * Sanity check the attributes for length.
682 */
683 switch (attr[0]) {
684 default: /* don't do anything by default */
685 break;
686
687 /*
688 * If there's an EAP-Message, we require
689 * a Message-Authenticator.
690 */
691 case FR_EAP_MESSAGE:
692 require_message_authenticator = true;
693 break;
694
695 case FR_MESSAGE_AUTHENTICATOR:
696 if (attr[1] != 2 + RADIUS_AUTH_VECTOR_LENGTH) {
697 FR_DEBUG_STRERROR_PRINTF("Message-Authenticator has invalid length (%d != 18) at offset %zd",
698 attr[1] - 2, attr - packet);
700 goto finish;
701 }
702 seen_ma = true;
703 break;
704 }
705
706 attr += attr[1];
707 num_attributes++; /* seen one more attribute */
708 }
709
710 /*
711 * If the attributes add up to a packet, it's allowed.
712 *
713 * If not, we complain, and throw the packet away.
714 */
715 if (attr != end) {
716 FR_DEBUG_STRERROR_PRINTF("attributes do NOT exactly fill the packet");
718 goto finish;
719 }
720
721 /*
722 * If we're configured to look for a maximum number of
723 * attributes, and we've seen more than that maximum,
724 * then throw the packet away, as a possible DoS.
725 */
726 if ((max_attributes > 0) &&
727 (num_attributes > max_attributes)) {
728 FR_DEBUG_STRERROR_PRINTF("Possible DoS attack - too many attributes in request (received %u, max %u are allowed).",
729 num_attributes, max_attributes);
731 goto finish;
732 }
733
734 /*
735 * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
736 *
737 * A packet with an EAP-Message attribute MUST also have
738 * a Message-Authenticator attribute.
739 *
740 * A Message-Authenticator all by itself is OK, though.
741 *
742 * Similarly, Status-Server packets MUST contain
743 * Message-Authenticator attributes.
744 */
745 if (require_message_authenticator && !seen_ma) {
746 FR_DEBUG_STRERROR_PRINTF("we require Message-Authenticator attribute, but it is not in the packet");
747 failure = DECODE_FAIL_MA_MISSING;
748 goto finish;
749 }
750
751finish:
752
753 if (reason) {
754 *reason = failure;
755 }
756 return (failure == DECODE_FAIL_NONE);
757}
758
759
760/** Verify a request / response packet
761 *
762 * This function does its work by calling fr_radius_sign(), and then
763 * comparing the signature in the packet with the one we calculated.
764 * If they differ, there's a problem.
765 *
766 * @param[in] packet the raw RADIUS packet (request or response)
767 * @param[in] vector the original packet vector
768 * @param[in] secret the shared secret
769 * @param[in] secret_len the length of the secret
770 * @param[in] require_message_authenticator whether we require Message-Authenticator.
771 * @param[in] limit_proxy_state whether we allow Proxy-State without Message-Authenticator.
772 * @return
773 * - -2 if the message authenticator or request authenticator was invalid.
774 * - -1 if we were unable to verify the shared secret, or the packet
775 * was in some other way malformed.
776 * - 0 on success.
777 */
778int fr_radius_verify(uint8_t *packet, uint8_t const *vector,
779 uint8_t const *secret, size_t secret_len,
780 bool require_message_authenticator, bool limit_proxy_state)
781{
782 bool found_message_authenticator = false;
783 bool found_proxy_state = false;
784 int rcode;
785 int code;
786 uint8_t *msg, *end;
787 size_t packet_len = fr_nbo_to_uint16(packet + 2);
788 uint8_t request_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
789 uint8_t message_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
790
791 if (packet_len < RADIUS_HEADER_LENGTH) {
792 fr_strerror_printf("invalid packet length %zu", packet_len);
793 return -1;
794 }
795
796 code = packet[0];
797 if (!code || (code >= FR_RADIUS_CODE_MAX)) {
798 fr_strerror_printf("Unknown reply code %d", code);
799 return -1;
800 }
801
802 memcpy(request_authenticator, packet + 4, sizeof(request_authenticator));
803
804 /*
805 * Find Message-Authenticator. Its value has to be
806 * calculated before we calculate the Request
807 * Authenticator or the Response Authenticator.
808 */
809 msg = packet + RADIUS_HEADER_LENGTH;
810 end = packet + packet_len;
811
812 while (msg < end) {
813 if ((end - msg) < 2) goto invalid_attribute;
814
815 if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
816 if (msg[1] < 2) goto invalid_attribute;
817
818 /*
819 * If we're not allowing Proxy-State without
820 * Message-authenticator, we need to record
821 * the fact we found Proxy-State.
822 */
823 if (limit_proxy_state && (msg[0] == FR_PROXY_STATE)) found_proxy_state = true;
824
825 if ((msg + msg[1]) > end) {
826 invalid_attribute:
827 fr_strerror_printf("invalid attribute at offset %zd", msg - packet);
828 return -1;
829 }
830 msg += msg[1];
831 continue;
832 }
833
834 if (msg[1] < 18) {
835 fr_strerror_const("too small Message-Authenticator");
836 return -1;
837 }
838
839 /*
840 * Found it, save a copy.
841 */
842 memcpy(message_authenticator, msg + 2, sizeof(message_authenticator));
843 found_message_authenticator = true;
844 break;
845 }
846
847 if (packet[0] == FR_RADIUS_CODE_ACCESS_REQUEST) {
848 if (limit_proxy_state && found_proxy_state && !found_message_authenticator) {
849 fr_strerror_const("Proxy-State is not allowed without Message-Authenticator");
850 return -1;
851 }
852
853 if (require_message_authenticator && !found_message_authenticator) {
854 fr_strerror_const("Access-Request is missing the required Message-Authenticator attribute");
855 return -1;
856 }
857 }
858
859 /*
860 * Overwrite the contents of Message-Authenticator
861 * with the one we calculate.
862 */
863 rcode = fr_radius_sign(packet, vector, secret, secret_len);
864 if (rcode < 0) {
865 fr_strerror_const_push("Failed calculating correct authenticator");
866 return -1;
867 }
868
869 /*
870 * Check the Message-Authenticator first.
871 *
872 * If it's invalid, restore the original
873 * Message-Authenticator and Request Authenticator
874 * fields.
875 *
876 * If it's valid the original and calculated
877 * message authenticators are the same, so we don't
878 * need to do anything.
879 */
880 if ((msg < end) &&
881 (fr_digest_cmp(message_authenticator, msg + 2, sizeof(message_authenticator)) != 0)) {
882 memcpy(msg + 2, message_authenticator, sizeof(message_authenticator));
883 memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
884
885 fr_strerror_const("invalid Message-Authenticator (shared secret is incorrect)");
886 return -2;
887 }
888
889 /*
890 * These are random numbers, so there's no point in
891 * comparing them.
892 */
893 if ((packet[0] == FR_RADIUS_CODE_ACCESS_REQUEST) || (packet[0] == FR_RADIUS_CODE_STATUS_SERVER)) {
894 return 0;
895 }
896
897 /*
898 * Check the Request Authenticator.
899 */
900 if (fr_digest_cmp(request_authenticator, packet + 4, sizeof(request_authenticator)) != 0) {
901 memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
902 if (vector) {
903 fr_strerror_const("invalid Response Authenticator (shared secret is incorrect)");
904 } else {
905 fr_strerror_const("invalid Request Authenticator (shared secret is incorrect)");
906 }
907 return -2;
908 }
909
910 return 0;
911}
912
913void *fr_radius_next_encodable(fr_dlist_head_t *list, void *current, void *uctx);
914
915void *fr_radius_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
916{
917 fr_pair_t *c = current;
918 fr_dict_t *dict = talloc_get_type_abort(uctx, fr_dict_t);
919
920 while ((c = fr_dlist_next(list, c))) {
921 PAIR_VERIFY(c);
922 if ((c->da->dict == dict) &&
923 (!c->da->flags.internal || ((c->da->attr > FR_TAG_BASE) && (c->da->attr < (FR_TAG_BASE + 0x20))))) {
924 break;
925 }
926 }
927
928 return c;
929}
930
931
934 // can be in Access-Accept
937
940
942
943 [ FR_RADIUS_CODE_COA_ACK ] = true,
944 [ FR_RADIUS_CODE_COA_NAK ] = true,
945
949
951};
952
954{
955 ssize_t slen;
956 fr_pair_t const *vp;
957 fr_dcursor_t cursor;
958 fr_dbuff_t work_dbuff, length_dbuff;
959
961
962 /*
963 * The RADIUS header can't do more than 64K of data.
964 */
965 work_dbuff = FR_DBUFF_MAX(dbuff, 65535);
966
967 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, packet_ctx->code, packet_ctx->id);
968 length_dbuff = FR_DBUFF(&work_dbuff);
970
971 switch (packet_ctx->code) {
974 packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
975
976 /*
977 * Allow over-rides of the authentication vector for testing.
978 */
980 if (vp && (vp->vp_length >= RADIUS_AUTH_VECTOR_LENGTH)) {
982 } else {
983 int i;
984
985 for (i = 0; i < 4; i++) {
986 FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t) fr_rand());
987 }
988 }
989 break;
990
1000 if (!packet_ctx->request_authenticator) {
1001 fr_strerror_const("Cannot encode response without request");
1002 return -1;
1003 }
1005 break;
1006
1009 /*
1010 * Tunnel-Password encoded attributes are allowed
1011 * in CoA-Request packets, by RFC 5176 Section
1012 * 3.6. HOWEVER, the tunnel passwords are
1013 * "encrypted" using the Request Authenticator,
1014 * which is all zeros! That makes them much
1015 * easier to decrypt. The only solution here is
1016 * to say "don't do that!"
1017 */
1019 packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
1020
1022 break;
1023
1024 default:
1025 fr_strerror_printf("Cannot encode unknown packet code %d", packet_ctx->code);
1026 return -1;
1027 }
1028
1029 /*
1030 * Always add Message-Authenticator after the packet
1031 * header for insecure transport protocols.
1032 */
1033 if (!packet_ctx->common->secure_transport) switch (packet_ctx->code) {
1039 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_MESSAGE_AUTHENTICATOR, 0x12,
1040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
1042 packet_ctx->seen_message_authenticator = true;
1043 }
1044
1045 /*
1046 * If we're sending Protocol-Error, add in
1047 * Original-Packet-Code manually. If the user adds it
1048 * later themselves, well, too bad.
1049 */
1050 if (packet_ctx->code == FR_RADIUS_CODE_PROTOCOL_ERROR) {
1051 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_EXTENDED_ATTRIBUTE_1, 0x07, 0x04 /* Original-Packet-Code */,
1052 0x00, 0x00, 0x00, packet_ctx->request_code);
1053 }
1054
1055 /*
1056 * Loop over the reply attributes for the packet.
1057 */
1059 while ((vp = fr_dcursor_current(&cursor))) {
1060 PAIR_VERIFY(vp);
1061
1062 /*
1063 * Encode an individual VP
1064 */
1065 slen = fr_radius_encode_pair(&work_dbuff, &cursor, packet_ctx);
1066 if (slen < 0) return slen;
1067 } /* done looping over all attributes */
1068
1069 /*
1070 * Add Proxy-State to the end of the packet if the caller requested it.
1071 */
1072 if (packet_ctx->add_proxy_state) {
1073 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_PROXY_STATE, (uint8_t) (2 + sizeof(packet_ctx->common->proxy_state)));
1074 FR_DBUFF_IN_RETURN(&work_dbuff, packet_ctx->common->proxy_state);
1075 }
1076
1077 /*
1078 * Fill in the length field we zeroed out earlier.
1079 *
1080 */
1081 fr_dbuff_in(&length_dbuff, (uint16_t) (fr_dbuff_used(&work_dbuff)));
1082
1083 FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "%s encoded packet", __FUNCTION__);
1084
1085 return fr_dbuff_set(dbuff, &work_dbuff);
1086}
1087
1089 uint8_t *packet, size_t packet_len,
1090 fr_radius_decode_ctx_t *decode_ctx)
1091{
1092 ssize_t slen;
1093 uint8_t const *attr, *end;
1094 static const uint8_t zeros[RADIUS_AUTH_VECTOR_LENGTH] = {};
1095
1096 if (!decode_ctx->request_authenticator) {
1097 switch (packet[0]) {
1100 decode_ctx->request_authenticator = packet + 4;
1101 break;
1102
1106 decode_ctx->request_authenticator = zeros;
1107 break;
1108
1109 default:
1110 fr_strerror_const("No authentication vector passed for packet decode");
1111 return -1;
1112 }
1113 }
1114
1115 if (decode_ctx->request_code) {
1116 unsigned int code = packet[0];
1117
1118 /*
1119 * Quiet the compiler, which gets excited about an out
1120 * of bounds access in allowed_replies
1121 */
1122 if (!fr_cond_assert(code < FR_RADIUS_CODE_MAX)) {
1123 return DECODE_FAIL_UNKNOWN_PACKET_CODE; /* checked by fr_radius_ok() */
1124 }
1125 if (!fr_cond_assert(decode_ctx->request_code < FR_RADIUS_CODE_MAX)) {
1126 return DECODE_FAIL_UNKNOWN_PACKET_CODE; /* checked by fr_radius_ok() */
1127 }
1128
1129 if (!allowed_replies[code]) {
1130 fr_strerror_printf("%s packet received unknown reply code %s",
1133 }
1134
1135 /*
1136 * Protocol error can reply to any packet.
1137 *
1138 * Status-Server can get any reply.
1139 *
1140 * Otherwise the reply code must be associated with the request code we sent.
1141 */
1143 (allowed_replies[code] != decode_ctx->request_code)) {
1144 fr_strerror_printf("%s packet received invalid reply code %s",
1147 }
1148 }
1149
1150 /*
1151 * We can skip verification for dynamic client checks, and where packets are unsigned as with
1152 * RADIUS/1.1.
1153 */
1154 if (decode_ctx->verify) {
1155 if (!decode_ctx->request_authenticator) decode_ctx->request_authenticator = zeros;
1156
1157 if (fr_radius_verify(packet, decode_ctx->request_authenticator,
1158 (uint8_t const *) decode_ctx->common->secret, decode_ctx->common->secret_length,
1159 decode_ctx->require_message_authenticator, decode_ctx->limit_proxy_state) < 0) {
1160 return -1;
1161 }
1162 }
1163
1164 attr = packet + 20;
1165 end = packet + packet_len;
1166
1167 /*
1168 * The caller MUST have called fr_radius_ok() first. If
1169 * he doesn't, all hell breaks loose.
1170 */
1171 while (attr < end) {
1172 slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), decode_ctx);
1173 if (slen < 0) return slen;
1174
1175 /*
1176 * If slen is larger than the room in the packet,
1177 * all kinds of bad things happen.
1178 */
1179 if (!fr_cond_assert(slen <= (end - attr))) {
1180 return -slen;
1181 }
1182
1183 attr += slen;
1184 talloc_free_children(decode_ctx->tmp_ctx);
1185 }
1186
1187 /*
1188 * We've parsed the whole packet, return that.
1189 */
1190 return packet_len;
1191}
1192
1193/** Simple wrapper for callers who just need a shared secret
1194 *
1195 */
1197 uint8_t *packet, size_t packet_len,
1198 uint8_t const *vector, char const *secret)
1199{
1200 ssize_t rcode;
1201 fr_radius_ctx_t common_ctx = {};
1202 fr_radius_decode_ctx_t packet_ctx = {};
1203
1204 common_ctx.secret = secret;
1205 common_ctx.secret_length = strlen(secret);
1206
1207 packet_ctx.common = &common_ctx;
1208 packet_ctx.tmp_ctx = talloc(ctx, uint8_t);
1209 packet_ctx.request_authenticator = vector;
1210 packet_ctx.end = packet + packet_len;
1211
1212 rcode = fr_radius_decode(ctx, out, packet, packet_len, &packet_ctx);
1213 talloc_free(packet_ctx.tmp_ctx);
1214
1215 return rcode;
1216}
1217
1219{
1220 if (instance_count > 0) {
1222 return 0;
1223 }
1224
1226
1228 fail:
1230 return -1;
1231 }
1232
1235 goto fail;
1236 }
1237
1238 return 0;
1239}
1240
1242{
1243 if (--instance_count != 0) return;
1244
1246}
1247
1249{
1251
1252 if (da->parent->type == FR_TYPE_STRUCT) {
1253 if (flags->extended) {
1254 fr_strerror_const("Attributes of type 'extended' cannot be used inside of a 'struct'");
1255 return false;
1256 }
1257
1258 if (flags->long_extended) {
1259 fr_strerror_const("Attributes of type 'long_extended' cannot be used inside of a 'struct'");
1260 return false;
1261 }
1262
1263
1264 if (flags->concat) {
1265 fr_strerror_const("Attributes of type 'concat' cannot be used inside of a 'struct'");
1266 return false;
1267 }
1268
1269 if (flags->has_tag) {
1270 fr_strerror_const("Attributes of type 'concat' cannot be used inside of a 'struct'");
1271 return false;
1272 }
1273
1274 if (flags->abinary) {
1275 fr_strerror_const("Attributes of type 'abinary' cannot be used inside of a 'struct'");
1276 return false;
1277 }
1278
1279 if (flags->encrypt > 0) {
1280 fr_strerror_const("Attributes of type 'encrypt' cannot be used inside of a 'struct'");
1281 return false;
1282 }
1283
1284 return true;
1285 }
1286
1287 if (da->flags.length > 253) {
1288 fr_strerror_printf("Attributes cannot be more than 253 octets in length");
1289 return false;
1290 }
1291 /*
1292 * Secret things are secret.
1293 */
1294 if (flags->encrypt != 0) da->flags.secret = true;
1295
1296 if (flags->concat) {
1297 if (!da->parent->flags.is_root) {
1298 fr_strerror_const("Attributes with the 'concat' flag MUST be at the root of the dictionary");
1299 return false;
1300 }
1301
1302 if (da->type != FR_TYPE_OCTETS) {
1303 fr_strerror_const("Attributes with the 'concat' flag MUST be of data type 'octets'");
1304 return false;
1305 }
1306
1307 return true; /* can't use any other flag */
1308 }
1309
1310 /*
1311 * Tagged attributes can only be of two data types. They
1312 * can, however, be VSAs.
1313 */
1314 if (flags->has_tag) {
1315 if ((da->type != FR_TYPE_UINT32) && (da->type != FR_TYPE_STRING)) {
1316 fr_strerror_printf("The 'has_tag' flag can only be used for attributes of type 'integer' "
1317 "or 'string'");
1318 return false;
1319 }
1320
1321 if (!(da->parent->flags.is_root ||
1322 ((da->parent->type == FR_TYPE_VENDOR) &&
1323 (da->parent->parent && da->parent->parent->type == FR_TYPE_VSA)))) {
1324 fr_strerror_const("The 'has_tag' flag can only be used with RFC and VSA attributes");
1325 return false;
1326 }
1327
1328 return true;
1329 }
1330
1331 if (flags->extended) {
1332 if (da->type != FR_TYPE_TLV) {
1333 fr_strerror_const("The 'long' or 'extended' flag can only be used for attributes of type 'tlv'");
1334 return false;
1335 }
1336
1337 if (!da->parent->flags.is_root) {
1338 fr_strerror_const("The 'long' flag can only be used for top-level RFC attributes");
1339 return false;
1340 }
1341
1342 return true;
1343 }
1344
1345 /*
1346 * Stupid hacks for MS-CHAP-MPPE-Keys. The User-Password
1347 * encryption method has no provisions for encoding the
1348 * length of the data. For User-Password, the data is
1349 * (presumably) all printable non-zero data. For
1350 * MS-CHAP-MPPE-Keys, the data is binary crap. So... we
1351 * MUST specify a length in the dictionary.
1352 */
1353 if ((flags->encrypt == RADIUS_FLAG_ENCRYPT_USER_PASSWORD) && (da->type != FR_TYPE_STRING)) {
1354 if (da->type != FR_TYPE_OCTETS) {
1355 fr_strerror_printf("The 'encrypt=User-Password' flag can only be used with "
1356 "attributes of type 'string'");
1357 return false;
1358 }
1359
1360 if (da->flags.length == 0) {
1361 fr_strerror_printf("The 'encrypt=User-Password' flag MUST be used with an explicit length for "
1362 "'octets' data types");
1363 return false;
1364 }
1365 }
1366
1367 switch (da->type) {
1368 case FR_TYPE_STRING:
1369 break;
1370
1371 case FR_TYPE_TLV:
1372 case FR_TYPE_IPV4_ADDR:
1373 case FR_TYPE_UINT32:
1374 case FR_TYPE_OCTETS:
1375 if (flags->encrypt != RADIUS_FLAG_ENCRYPT_ASCEND_SECRET) break;
1377
1378 default:
1379 if (flags->encrypt) {
1380 fr_strerror_printf("The 'encrypt' flag cannot be used with attributes of type '%s'",
1381 fr_type_to_str(da->type));
1382 return false;
1383 }
1384 }
1385
1386 return true;
1387}
1388
1391 .name = "radius",
1392 .default_type_size = 1,
1393 .default_type_length = 1,
1394 .attr = {
1395 .flags = {
1396 .table = radius_flags,
1397 .table_len = NUM_ELEMENTS(radius_flags),
1398 .len = sizeof(fr_radius_attr_flags_t),
1399 },
1400 .valid = attr_valid,
1401 },
1402
1403 .init = fr_radius_global_init,
1404 .free = fr_radius_global_free,
1405
1406 .decode = fr_radius_decode_foreign,
1407 .encode = fr_radius_encode_foreign,
1408};
static int const char char buffer[256]
Definition acutest.h:576
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define STRINGIFY(x)
Definition build.h:197
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#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:767
#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:673
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:911
#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:1004
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#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:1508
#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:1382
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
Definition dbuff.h:1350
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
Definition dbuff.h:1567
#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:1585
#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:1472
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:337
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
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:853
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
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:4090
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:171
#define fr_dict_autoload(_to_load)
Definition dict.h:850
static fr_slen_t in
Definition dict.h:824
char const * name
name of this protocol
Definition dict.h:430
#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:408
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
Protocol specific custom flag definitnion.
Definition dict.h:398
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:429
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:140
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: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::@130 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:93
fr_dict_attr_t const * attr_state
Definition base.c:103
fr_dict_attr_t const * attr_eap_message
Definition base.c:96
fr_dict_t const * dict_radius
Definition base.c:78
fr_dict_attr_t const * attr_message_authenticator
Definition base.c:94
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
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:442
fr_md5_final_t fr_md5_final
Definition md5.c:443
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition md5.c:522
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition md5.c:477
void fr_md5_ctx_t
Definition md5.h:28
#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:472
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: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:693
static uint8_t const zeros[6]
Definition base.c:93
static bool attr_valid(fr_dict_attr_t *da)
Definition base.c:443
fr_dict_protocol_t libfreeradius_radius_dict_protocol
Definition base.c:1390
fr_dict_autoload_t libfreeradius_radius_dict[]
Definition base.c:47
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:932
void * fr_radius_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
Definition base.c:915
static fr_dict_flag_parser_t const radius_flags[]
Definition base.c:218
fr_dict_attr_t const * attr_packet_authentication_vector
Definition base.c:54
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:172
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:247
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:1088
size_t fr_radius_limit_proxy_state_table_len
Definition base.c:99
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:358
int fr_radius_verify(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len, bool require_message_authenticator, bool limit_proxy_state)
Verify a request / response packet.
Definition base.c:778
fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[]
Definition base.c:64
size_t fr_radius_require_ma_table_len
Definition base.c:90
fr_dict_attr_t const * attr_chap_challenge
Definition base.c:55
fr_dict_attr_t const * attr_vendor_specific
Definition base.c:60
int fr_radius_global_init(void)
Definition base.c:1218
size_t fr_radius_request_name_table_len
Definition base.c:110
#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:1196
void fr_radius_global_free(void)
Definition base.c:1241
fr_table_num_sorted_t const fr_radius_limit_proxy_state_table[]
Definition base.c:92
fr_table_num_sorted_t const fr_radius_request_name_table[]
Definition base.c:101
fr_table_num_sorted_t const fr_radius_require_ma_table[]
Definition base.c:83
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:515
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
Definition base.c:953
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:112
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:285
int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
Definition base.c:227
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:2088
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:1983
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:1515
ssize_t fr_radius_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
Definition encode.c:1680
VQP attributes.
static rc_request_t * current
static char * secret
unsigned int has_tag
Attribute has a tag.
Definition radius.h:156
bool secure_transport
for TLS
Definition radius.h:98
@ FR_RADIUS_REQUIRE_MA_NO
Do not require Message-Authenticator.
Definition radius.h:63
@ FR_RADIUS_REQUIRE_MA_YES
Require Message-Authenticator.
Definition radius.h:64
@ FR_RADIUS_REQUIRE_MA_AUTO
Only require Message-Authenticator if we've previously received a packet from this client with Messag...
Definition radius.h:65
fr_radius_ctx_t const * common
Definition radius.h:104
uint8_t request_code
original code for the request.
Definition radius.h:132
uint8_t const * request_authenticator
Definition radius.h:127
unsigned int abinary
Attribute is in "abinary" format.
Definition radius.h:157
fr_radius_decode_fail_t
Failure reasons.
Definition radius.h:162
@ DECODE_FAIL_INVALID_ATTRIBUTE
Definition radius.h:170
@ DECODE_FAIL_ATTRIBUTE_UNDERFLOW
Definition radius.h:174
@ DECODE_FAIL_MIN_LENGTH_FIELD
Definition radius.h:166
@ DECODE_FAIL_HEADER_OVERFLOW
Definition radius.h:168
@ DECODE_FAIL_ATTRIBUTE_TOO_SHORT
Definition radius.h:171
@ DECODE_FAIL_ATTRIBUTE_OVERFLOW
Definition radius.h:172
@ DECODE_FAIL_TOO_MANY_ATTRIBUTES
Definition radius.h:175
@ DECODE_FAIL_NONE
Definition radius.h:163
@ DECODE_FAIL_MIN_LENGTH_PACKET
Definition radius.h:164
@ DECODE_FAIL_MIN_LENGTH_MISMATCH
Definition radius.h:167
@ DECODE_FAIL_MA_INVALID_LENGTH
Definition radius.h:173
@ DECODE_FAIL_MA_MISSING
Definition radius.h:176
@ DECODE_FAIL_UNKNOWN_PACKET_CODE
Definition radius.h:169
bool disallow_tunnel_passwords
not all packets can have tunnel passwords
Definition radius.h:120
char const * secret
Definition radius.h:95
unsigned int concat
Attribute is concatenated.
Definition radius.h:155
uint8_t const * end
end of the packet
Definition radius.h:130
bool limit_proxy_state
Don't allow Proxy-State in requests.
Definition radius.h:137
uint64_t proxy_state
Definition radius.h:100
uint8_t const * request_authenticator
Definition radius.h:106
unsigned int extended
Attribute is an extended attribute.
Definition radius.h:154
fr_radius_attr_flags_encrypt_t encrypt
Attribute is encrypted.
Definition radius.h:158
bool require_message_authenticator
Definition radius.h:136
size_t secret_length
Definition radius.h:96
bool verify
can skip verify for dynamic clients
Definition radius.h:135
fr_radius_ctx_t const * common
Definition radius.h:125
@ FR_RADIUS_LIMIT_PROXY_STATE_NO
Do not limit Proxy-State.
Definition radius.h:77
@ FR_RADIUS_LIMIT_PROXY_STATE_AUTO
Do not allow Proxy-State unless:
Definition radius.h:82
@ FR_RADIUS_LIMIT_PROXY_STATE_YES
Limit Proxy-State.
Definition radius.h:79
unsigned int long_extended
Attribute is a long extended attribute.
Definition radius.h:153
fr_radius_attr_flags_encrypt_t
Definition radius.h:144
@ RADIUS_FLAG_ENCRYPT_INVALID
Invalid encryption flag.
Definition radius.h:145
@ RADIUS_FLAG_ENCRYPT_USER_PASSWORD
Encrypt attribute RFC 2865 style.
Definition radius.h:147
@ RADIUS_FLAG_ENCRYPT_ASCEND_SECRET
Encrypt attribute ascend style.
Definition radius.h:149
@ RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD
Encrypt attribute RFC 2868 style.
Definition radius.h:148
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:186
bool add_proxy_state
do we add a Proxy-State?
Definition radius.h:119
bool seen_message_authenticator
Definition radius.h:121
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition radius.h:129
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
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:653
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:569
#define PAIR_VERIFY(_x)
Definition pair.h:191
#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
static size_t char fr_sbuff_t size_t inlen
Definition value.h:997
static size_t char ** out
Definition value.h:997