]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
implement and document "require_message_authenticator = auto"
authorAlan T. DeKok <aland@freeradius.org>
Sun, 30 Jun 2024 01:53:48 +0000 (21:53 -0400)
committerMatthew Newton <matthew-git@newtoncomputing.co.uk>
Mon, 8 Jul 2024 19:40:57 +0000 (20:40 +0100)
12 files changed:
raddb/clients.conf
raddb/proxy.conf
raddb/radiusd.conf.in
src/include/clients.h
src/include/libradius.h
src/include/radiusd.h
src/include/realms.h
src/main/client.c
src/main/listen.c
src/main/mainconfig.c
src/main/process.c
src/main/realms.c

index 0649aa391ecc9eef04e02c061187a29b8353ee51..28bd6863b583f2f3d846fbed5c3ac406dd983cc5 100644 (file)
@@ -118,13 +118,25 @@ client localhost {
        #
        #  The global configuration "security.require_message_authenticator"
        #  flag sets the default for all clients.  That default can be
-       #  over-ridden here, by setting it to "no".
+       #  over-ridden here, by setting it to a value.  If no value is set,
+       #  then the default from the "radiusd.conf" file is used.
+       #
+       #  See that file for full documentation on the flag, along
+       #  with allowed values and meanings.
        #
        #  This flag exists solely for legacy clients which do not send
        #  Message-Authenticator in all Access-Request packets.  We do not
        #  recommend setting it to "no".
        #
-       #  allowed values: yes, no
+       #  The number one way to protect yourself from the BlastRADIUS
+       #  attack is to update all RADIUS servers, and then set this
+       #  flag to "yes".  If all RADIUS servers are updated, and if
+       #  all of them have this flag set to "yes" for all clients,
+       #  then your network is safe.  You can then upgrade the
+       #  clients when it is convenient, instead of rushing the
+       #  upgrades.
+       #
+       #  allowed values: yes, no, auto
        #
 #      require_message_authenticator = no
 
@@ -133,11 +145,14 @@ client localhost {
        #  flag sets the default for all clients.  That default can be
        #  over-ridden here, by setting it to "no".
        #
+       #  See that file for full documentation on the flag, along
+       #  with allowed values,and meanings.
+       #
        #  This flag exists solely for legacy clients which do not send
        #  Message-Authenticator in all Access-Request packets.  We do not
        #  recommend setting it to "no".
        #
-       #  allowed values: yes, no
+       #  allowed values: yes, no, auto
        #
 #      limit_proxy_state = yes
 
index e0be4c04971a46845ffcf7281a6af8b5450422d5..7295538d5eb1a18ef69bb07e4cba7f31d8b53e00 100644 (file)
@@ -253,14 +253,18 @@ home_server localhost {
        #
        #  The global configuration "security.require_message_authenticator"
        #  flag sets the default for all home servers.  That default can be
-       #  over-ridden here, by setting it to "no".
+       #  over-ridden here, by setting it to a value.  If no value is set,
+       #  then the default from the "radiusd.conf" file is used.
+       #
+       #  See that file for full documentation on the flag, along
+       #  with allowed values and meanings.
        #
        #  This flag exists solely for legacy home servers which do
        #  not send Message-Authenticator in all Access-Accept,
        #  Access-Reject, or Access-Challenge packets.  We do not
        #  recommend setting it to "no".
        #
-       #  allowed values: yes, no
+       #  allowed values: yes, no, auto
        #
 #      require_message_authenticator = no
 
index 2188b70120de31257c1627d522420d6171e67584..7f46038a0d9c6dedacf3303104921f7798f13bd4 100644 (file)
@@ -626,25 +626,102 @@ security {
        status_server = yes
 
        #
-       #  Global configuration for requiring Message-Authenticator
-       #  in all Access-* packets sent over UDP or TCP.  This flag
-       #  is ignored for TLS.
+       #  Global configuration for requiring Message-Authenticator in
+       #  all Access-* packets sent over UDP or TCP.  This flag is
+       #  ignored for TLS.
+       #
+       #  The number one way to protect yourself from the BlastRADIUS
+       #  attack is to update all RADIUS servers, and then set this
+       #  flag to "yes".  If all RADIUS servers are updated, and if
+       #  all of them have this flag set to "yes" for all clients,
+       #  then your network is safe.  You can then upgrade the
+       #  clients when it is convenient, instead of rushing the
+       #  upgrades.
        #
        #  This flag sets the global default for all clients and home
        #  servers.  It can be over-ridden in an individual client or
-       #  home server definition by adding a flag to that section:
+       #  home_server definition by adding the same flag to that
+       #  section with an appropriate value.
+       #
+       #  All upgraded RADIUS implementations should send
+       #  Message-Authenticator in all Access-Request, Access-Accept,
+       #  Access-Reject, and Access-Challenge packets.  Once all
+       #  systems are upgraded, setting this flag to "yes" is the
+       #  best protection from the attack.
+       #
+       #  The possible values and meanings for
+       #  "require_message_authenticator" are;
+       #
+       #  * "no" - allow Access-* packet which do not contain
+       #    Message-Authenticator
+       #
+       #    For a client, if this flag is set to "no", then the
+       #    "limit_proxy_state" flag, below, is also checked.
+       #
+       #    For a home_server, if this flag is set to "no", then the
+       #    Access-Accept, Access-Reject, and Access-Challenge
+       #    packets do not need to contain Message-Authenticator.
+       #
+       #    The only reason to set this flag to "no" is when the
+       #    RADIUS client or home server has not been updated.  It is
+       #    always safer to set this flag "no" in the individual
+       #    client or home_server definition.  The global flag SHOULD
+       #    still be set to a safe value: "yes".
+       #
+       #    WARNING: Setting this flag and the "limit_proxy_state"
+       #    flag to "no" will allow MITM attackers to create fake
+       #    Access-Accept packets to the NAS!  At least one of them
+       #    MUST be set to "yes" for the system to have any
+       #    protection against the attack.
+       #
+       #  * "yes" - Require that all Access-* packets (client and
+       #    home_server) contain Message-Authenticator.  If a packet
+       #    does not contain Message-Authenticator, then it is
+       #    discarded.
+       #
+       #  * "auto" - Automatically determine the value of the flag,
+       #    based on the first packet received from that client or
+       #    home_server.
+       #
+       #    If the packet does not contain Message-Authenticator,
+       #    then the value of the flag is automatically switched to
+       #    "no".
+       #
+       #    If the packet contains Message-Authenticator but not
+       #    EAP-Message, then the value of the flag is automatically
+       #    switched to "yes".  The server has to check for
+       #    EAP-Message, because the previous RFCs require that the
+       #    packet contains Message-Authenticator when it also
+       #    contains EAP-Message.  So having a Message-Authenticator
+       #    in those packets doesn't give the server enough
+       #    information to determined if the client or home_server
+       #    has been updated.
+       #
+       #    If the packet contains Message-Authenticator and
+       #    EAP-Message, then the flag is left at the "auto" value.
+       #
+       #    WARNING: This switch is done for the first packet
+       #    received from that client or home server.  The change
+       #    does NOT persist across server restarts.  You MUST change
+       #    the to "yes" manually, in order to make a permanent
+       #    change to the configuration.
        #
-       #       require_message_authenticator = no
+       #    WARNING: If there are multiple NASes with the same source
+       #    IP and client definitions, BUT the NASes have different
+       #    behavior, then this flag WILL LIKELY BREAK YOUR NETWORK.
        #
-       #  If the server produces error message which says "Packet
-       #  does not contain required Message-Authenticator attribute",
-       #  then this configuration item has to be updated.
+       #    That is, when there are multiple different RADIUS clients
+       #    behind one NATed IP address, then these security settings
+       #    have to be set to allow the MOST INSECURE packets to be
+       #    processed.  This is a terrible idea, and will leave your
+       #    network vulnerable to the attack.  Please upgrade all
+       #    clients immediately.
        #
-       #  WARNING: This item should always be left as "yes",
-       #  otherwise it is possible for MITM attackers to create fake
-       #  Access-Accept packets to the NAS!
+       #    The only solution to that rare configuration is to set
+       #    this flag to "no", in which case the network will work,
+       #    but will be vulnerable to the attack.
        #
-       require_message_authenticator = yes
+       require_message_authenticator = auto
 
        #
        #  Global configuration for limiting the combination of
@@ -654,7 +731,7 @@ security {
        #
        #  This flag sets the global default for all clients.  It can
        #  be over-ridden in an individual client definition by adding
-       #  the same flag to that section with an appropriate value:
+       #  the same flag to that section with an appropriate value.
        #
        #  If "require_message_authenticator" is set to "yes", this
        #  configuration item is ignored.
@@ -713,6 +790,13 @@ security {
        #    IP and client definitions, BUT the NASes have different
        #    behavior, then this flag WILL LIKELY BREAK YOUR NETWORK.
        #
+       #    That is, when there are multiple different RADIUS clients
+       #    behind one NATed IP address, then these security settings
+       #    have to be set to allow the MOST INSECURE packets to be
+       #    processed.  This is a terrible idea, and will leave your
+       #    network vulnerable to the attack.  Please upgrade all
+       #    clients immediately.
+       #
        #    The only solution to that rare configuration is to set
        #    this flag to "no", in which case the network will work,
        #    but will be vulnerable to the attack.
index a9b66429cca58219e2a3d7788bca44eda5e6c362..7d3288a4899e4e879a79c04227cda0f3af86fc77 100644 (file)
  * @copyright 2015 The FreeRADIUS server project
  */
 
-typedef enum {
-       FR_BOOL_FALSE = 0,
-       FR_BOOL_TRUE,
-       FR_BOOL_AUTO,
-} fr_bool_auto_t;
-
-
 typedef struct radclient_list RADCLIENT_LIST;
 
 
@@ -50,7 +43,9 @@ typedef struct radclient {
 
        char const              *secret;                //!< Secret PSK.
 
-       bool                    require_ma;             //!< Require RADIUS message authenticator in requests.
+       fr_bool_auto_t          require_ma;             //!< Require RADIUS message authenticator in requests.
+
+       bool                    dynamic_require_ma;     //!< for dynamic clients
 
        fr_bool_auto_t          limit_proxy_state;      //!< Limit Proxy-State in requests
 
index 3faab756b5c57cc9b8159339a2d2c81126aeb2c8..1b975517b5f1bd572a38d03dcc3a908e8b83f1c9 100644 (file)
@@ -953,6 +953,12 @@ int                fr_socket_wait_for_connect(int sockfd, struct timeval *timeout);
 }
 #endif
 
+typedef enum {
+       FR_BOOL_FALSE = 0,
+       FR_BOOL_TRUE,
+       FR_BOOL_AUTO,
+} fr_bool_auto_t;
+
 #include <freeradius-devel/packet.h>
 
 #ifdef WITH_TCP
index 36e57411587877839268160ba844b1a23769571d..2b9bc19f1521ec0d9c051ab78bc64d1a1b7f7a20 100644 (file)
@@ -174,7 +174,7 @@ typedef struct main_config {
 
        bool            exiting;                        //!< are we exiting?
 
-       bool            require_ma;                     //!< global configuration for all clients and home servers
+       fr_bool_auto_t  require_ma;                     //!< global configuration for all clients and home servers
 
        fr_bool_auto_t  limit_proxy_state;              //!< global configuration for all clients
 
index 0a5132611dcd1ad353bb86a5023dfad713ac3208..171a4491121c4385c2d861f25e61fa794f76a82e 100644 (file)
@@ -64,7 +64,7 @@ typedef struct home_server {
        bool                    dual;                   //!< One of a pair of homeservers on consecutive ports.
        bool                    dynamic;                //!< is this a dynamically added home server?
        bool                    nonblock;               //!< Enable a socket non-blocking to the home server.
-       bool                    require_ma;             //!< for all replies to Access-Request and Status-Server
+       fr_bool_auto_t          require_ma;             //!< for all replies to Access-Request and Status-Server
 
        char const              *virtual_server;                //!< For internal proxying
        char const              *parent_server;
index 027839b4f6d5d1f5a35780c719271aee3a0e4666..c5330431be64955b050dad50feac9fe3df930113 100644 (file)
@@ -491,6 +491,7 @@ static fr_ipaddr_t cl_ipaddr;
 static uint32_t cl_netmask;
 static char const *cl_srcipaddr = NULL;
 static char const *hs_proto = NULL;
+static char const *require_message_authenticator = NULL;
 static char const *limit_proxy_state = NULL;
 
 #ifdef WITH_TCP
@@ -514,7 +515,7 @@ static const CONF_PARSER client_config[] = {
 
        { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL },
 
-       { "require_message_authenticator",  FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_IGNORE_DEFAULT, RADCLIENT, require_ma), NULL },
+       { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_STRING| PW_TYPE_IGNORE_DEFAULT, &require_message_authenticator), NULL },
        { "limit_proxy_state", FR_CONF_POINTER(PW_TYPE_STRING| PW_TYPE_IGNORE_DEFAULT, &limit_proxy_state), NULL },
 
        { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL },
@@ -723,7 +724,7 @@ static const CONF_PARSER dynamic_config[] = {
        { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL },
        { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL },
 
-       { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, require_ma), NULL },
+       { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, dynamic_require_ma), NULL },
 
        { "FreeRADIUS-Client-Secret",  FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" },
        { "FreeRADIUS-Client-Shortname",  FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" },
@@ -916,6 +917,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bo
 
        memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
        cl_netmask = 255;
+       require_message_authenticator = NULL;
        limit_proxy_state = NULL;
 
        if (cf_section_parse(cs, c, client_config) < 0) {
@@ -926,6 +928,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bo
                hs_proto = NULL;
                cl_srcipaddr = NULL;
 #endif
+               require_message_authenticator = NULL;
                limit_proxy_state = NULL;
 
                return NULL;
@@ -1185,10 +1188,16 @@ done_coa:
        }
 #endif
 
-       if (fr_bool_auto_parse(cf_pair_find(cs, "limit_proxy_state"), &c->limit_proxy_state, limit_proxy_state) < 0) {
+       if (fr_bool_auto_parse(cf_pair_find(cs, "require_message_authenticator"), &c->require_ma, require_message_authenticator) < 0) {
                goto error;
        }
 
+       if (c->require_ma != FR_BOOL_TRUE) {
+               if (fr_bool_auto_parse(cf_pair_find(cs, "limit_proxy_state"), &c->limit_proxy_state, limit_proxy_state) < 0) {
+                       goto error;
+               }
+       }
+
        return c;
 }
 
@@ -1513,6 +1522,11 @@ validate:
                goto error;
        }
 
+       /*
+        *      It can't be set to "auto".  Too bad.
+        */
+       c->require_ma = (fr_bool_auto_t) c->dynamic_require_ma;
+
        if (!client_add_dynamic(clients, request->client, c)) {
                return NULL;
        }
index 8f8e1146fd09dbb1c14c9ca72ea4050438c94944..2a8c7ecac5ad93ea3b790bbbd5e0769c66de0b16 100644 (file)
@@ -504,7 +504,49 @@ int rad_status_server(REQUEST *request)
 
 static void blastradius_checks(RADIUS_PACKET *packet, RADCLIENT *client)
 {
-       if (client->require_ma) return;
+       if (client->require_ma == FR_BOOL_TRUE) return;
+
+       if (client->require_ma == FR_BOOL_AUTO) {
+               if (!packet->message_authenticator) {
+                       ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                       ERROR("BlastRADIUS check: Received packet without Message-Authenticator.");
+                       ERROR("Setting \"require_message_authenticator = false\" for client %s", client->shortname);
+                       ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                       ERROR("UPGRADE THE CLIENT AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK.");
+                       ERROR("Once the client is upgraded, set \"require_message_authenticator = true\" for this client.");
+                       ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                       client->require_ma = FR_BOOL_FALSE;
+
+                       /*
+                        *      And fall through to the
+                        *      limit_proxy_state checks, which might
+                        *      complain again.  Oh well, maybe that
+                        *      will make people read the messages.
+                        */
+
+               } else if (packet->eap_message) {
+                       /*
+                        *      Don't set it to "true" for packets
+                        *      with EAP-Message.  It's already
+                        *      required there, and we might get a
+                        *      non-EAP packet with (or without)
+                        *      Message-Authenticator
+                        */
+                       return;
+               } else {
+                       ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                       ERROR("BlastRADIUS check: Received packet with Message-Authenticator.");
+                       ERROR("Setting \"require_message_authenticator = true\" for client %s", client->shortname);
+                       ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                       ERROR("It looks like the client has been uppdated to protect from the BlastRADIUS attack.");
+                       ERROR("Please set \"require_message_authenticator = true\" for this client.");
+                       ERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
+                       client->require_ma = FR_BOOL_TRUE;
+                       return;
+               }
+
+       }
 
        /*
         *      If all of the checks are turned off, then complain for every packet we receive.
@@ -515,6 +557,8 @@ static void blastradius_checks(RADIUS_PACKET *packet, RADCLIENT *client)
                 */
                if (packet->message_authenticator) return;
 
+               if (!fr_debug_lvl) return; /* easier than checking for each line below */
+
                DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                DEBUG("BlastRADIUS check: Received packet without Message-Authenticator.");
                DEBUG("YOU MUST SET \"require_message_authenticator = true\", or");
@@ -655,7 +699,7 @@ static int dual_tcp_recv(rad_listen_t *listener)
                /*
                 *      Enforce BlastRADIUS checks on TCP, too.
                 */
-               if (!rad_packet_ok(packet, client->require_ma | ((client->limit_proxy_state == FR_BOOL_TRUE) << 2), NULL)) {
+               if (!rad_packet_ok(packet, (client->require_ma == FR_BOOL_TRUE) | ((client->limit_proxy_state == FR_BOOL_TRUE) << 2), NULL)) {
                        FR_STATS_INC(auth, total_malformed_requests);
                        rad_free(&sock->packet);
                        return 0;
@@ -1755,7 +1799,7 @@ static int auth_socket_recv(rad_listen_t *listener)
         *      Now that we've sanity checked everything, receive the
         *      packet.
         */
-       packet = rad_recv(ctx, listener->fd, client->require_ma | ((client->limit_proxy_state == FR_BOOL_TRUE) << 2));
+       packet = rad_recv(ctx, listener->fd, (client->require_ma == FR_BOOL_TRUE) | ((client->limit_proxy_state == FR_BOOL_TRUE) << 2));
        if (!packet) {
                FR_STATS_INC(auth, total_malformed_requests);
                if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
@@ -2182,7 +2226,7 @@ static int proxy_socket_recv(rad_listen_t *listener)
 #endif
        char            buffer[128];
 
-       packet = rad_recv(NULL, listener->fd, 8); /* SOME packets don't require a Message-Authenticator attribute */
+       packet = rad_recv(NULL, listener->fd, 0x08); /* SOME packets don't require a Message-Authenticator attribute */
        if (!packet) {
                if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
                return 0;
index 2b1c568c33744cebd6ce94aba23b7b8cceb9195e..957bff933f1ce24f366b22aefde08590b0344ec5 100644 (file)
@@ -73,6 +73,7 @@ static char const *gid_name = NULL;
 static char const *chroot_dir = NULL;
 static bool allow_core_dumps = false;
 static char const *radlog_dest = NULL;
+static char const *require_message_authenticator = NULL;
 static char const *limit_proxy_state = NULL;
 
 /*
@@ -207,7 +208,7 @@ static const CONF_PARSER security_config[] = {
        { "max_attributes",  FR_CONF_POINTER(PW_TYPE_INTEGER, &fr_max_attributes), STRINGIFY(0) },
        { "reject_delay",  FR_CONF_POINTER(PW_TYPE_TIMEVAL, &main_config.reject_delay), STRINGIFY(0) },
        { "status_server", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.status_server), "no"},
-       { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.require_ma), "yes"},
+       { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_STRING, &require_message_authenticator), "auto"},
        { "limit_proxy_state", FR_CONF_POINTER(PW_TYPE_STRING, &limit_proxy_state), "auto"},
 #ifdef ENABLE_OPENSSL_VERSION_CHECK
        { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"},
@@ -904,6 +905,7 @@ int main_config_init(void)
        if (!main_config.dictionary_dir) {
                main_config.dictionary_dir = DICTDIR;
        }
+       main_config.require_ma = FR_BOOL_AUTO;
        main_config.limit_proxy_state = FR_BOOL_AUTO;
 
        /*
@@ -1204,8 +1206,13 @@ do {\
                CONF_PAIR *cp = NULL;
 
                subcs = cf_section_sub_find(cs, "security");
-               if (subcs) cp = cf_pair_find(subcs, "limit_proxy_state");
+               if (subcs) cp = cf_pair_find(subcs, "require_message_authenticator");
+               if (fr_bool_auto_parse(cp, &main_config.require_ma, require_message_authenticator) < 0) {
+                       cf_file_free(cs);
+                       return -1;
+               }
 
+               if (subcs) cp = cf_pair_find(subcs, "limit_proxy_state");
                if (fr_bool_auto_parse(cp, &main_config.limit_proxy_state, limit_proxy_state) < 0) {
                        cf_file_free(cs);
                        return -1;
index 251cb6b75dece550346a66b1f51bcf24b88f83a7..9db24e31e7b1a51eaf04a518a59132b1b4e673bd 100644 (file)
@@ -2708,7 +2708,7 @@ int request_proxy_reply(RADIUS_PACKET *packet)
                 *
                 *      The realms.c file already clears require_ma for TLS connections.
                 */
-               bool require_ma = request->home_server->require_ma && (request->proxy->code == PW_CODE_ACCESS_REQUEST);
+               bool require_ma = (request->home_server->require_ma == FR_BOOL_TRUE) && (request->proxy->code == PW_CODE_ACCESS_REQUEST);
 
                if (!request->home_server) {
                        proxy_reply_too_late(request);
@@ -2725,6 +2725,53 @@ int request_proxy_reply(RADIUS_PACKET *packet)
                        DEBUG("Ignoring spoofed proxy reply.  Signature is invalid");
                        return 0;
                }
+
+               /*
+                *      BlastRADIUS checks.  We're running in the main
+                *      listener thread, so there's no conflict
+                *      checking or setting these fields.
+                */
+               if ((request->proxy->code == PW_CODE_ACCESS_REQUEST) && 
+#ifdef WITH_TLS
+                   !request->home_server->tls &&
+#endif
+                   !packet->eap_message) {
+                       if (request->home_server->require_ma == FR_BOOL_AUTO) {
+                               if (!packet->message_authenticator) {
+                                       RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                                       RERROR("BlastRADIUS check: Received response to Access-Request without Message-Authenticator.");
+                                       RERROR("Setting \"require_message_authenticator = false\" for home_server %s", request->home_server->name);
+                                       RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                                       RERROR("UPGRADE THE HOME SERVER AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK.");
+                                       RERROR("Once the home_server is upgraded, set \"require_message_authenticator = true\" for this home_server.");
+                                       RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
+                                       request->home_server->require_ma = FR_BOOL_FALSE;
+                               } else {
+                                       RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                                       RERROR("BlastRADIUS check: Received response to Access-Request with Message-Authenticator.");
+                                       RERROR("Setting \"require_message_authenticator = true\" for home_server %s", request->home_server->name);
+                                       RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                                       RERROR("It looks like the home server has been uppdated to protect from the BlastRADIUS attack.");
+                                       RERROR("Please set \"require_message_authenticator = true\" for this home_server.");
+                                       RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
+                                       request->home_server->require_ma = FR_BOOL_TRUE;
+                               }
+
+                       } else if (fr_debug_lvl && (request->home_server->require_ma == FR_BOOL_FALSE) && !packet->message_authenticator) {
+                               /*
+                                *      If it's "no" AND we don't have a Message-Authenticator, then complain on every packet.
+                                */
+                               RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                               RDEBUG("BlastRADIUS check: Received packet without Message-Authenticator from home_server %s", request->home_server->name);
+                               RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                               RDEBUG("The packet does not contain Message-Authenticator, which is a security issue");
+                               RDEBUG("UPGRADE THE HOME SERVER AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK.");
+                               RDEBUG("Once the home server is upgraded, set \"require_message_authenticator = true\" for this home_server.");
+                               RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+                       }
+               }
        }
 
        /*
index 991496cac0e86b2b49520b269e972f2d9946111c..3f2c37270c4ba501baa71bf87eedcdbfab6a1d82 100644 (file)
@@ -435,9 +435,11 @@ static CONF_PARSER home_server_coa[] = {
 };
 #endif
 
+static const char *require_message_authenticator = NULL;
+
 static CONF_PARSER home_server_config[] = {
        { "nonblock", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, home_server_t, nonblock), "no" },
-       { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_IGNORE_DEFAULT, home_server_t, require_ma), NULL },
+       { "require_message_authenticator", FR_CONF_POINTER(PW_TYPE_STRING| PW_TYPE_IGNORE_DEFAULT, &require_message_authenticator), NULL },
        { "ipaddr", FR_CONF_OFFSET(PW_TYPE_COMBO_IP_ADDR, home_server_t, ipaddr), NULL },
        { "ipv4addr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, home_server_t, ipaddr), NULL },
        { "ipv6addr", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, home_server_t, ipaddr), NULL },
@@ -726,12 +728,18 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
        home->proto = IPPROTO_UDP;
        home->require_ma = main_config.require_ma;
 
+       require_message_authenticator = false;
+
        /*
         *      Parse the configuration into the home server
         *      struct.
         */
        if (cf_section_parse(cs, home, home_server_config) < 0) goto error;
 
+       if (fr_bool_auto_parse(cf_pair_find(cs, "require_message_authenticator"), &home->require_ma, require_message_authenticator) < 0) {
+               goto error;
+       }
+
        /*
         *      It has an IP address, it must be a remote server.
         */