From: Alan T. DeKok Date: Sun, 30 Jun 2024 01:53:48 +0000 (-0400) Subject: implement and document "require_message_authenticator = auto" X-Git-Tag: release_3_0_27~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bf190f9a0e2d79677edbeb76e5b4ae0a959f5f7f;p=thirdparty%2Ffreeradius-server.git implement and document "require_message_authenticator = auto" --- diff --git a/raddb/clients.conf b/raddb/clients.conf index 0649aa391e..28bd6863b5 100644 --- a/raddb/clients.conf +++ b/raddb/clients.conf @@ -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 diff --git a/raddb/proxy.conf b/raddb/proxy.conf index e0be4c0497..7295538d5e 100644 --- a/raddb/proxy.conf +++ b/raddb/proxy.conf @@ -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 diff --git a/raddb/radiusd.conf.in b/raddb/radiusd.conf.in index 2188b70120..7f46038a0d 100644 --- a/raddb/radiusd.conf.in +++ b/raddb/radiusd.conf.in @@ -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. diff --git a/src/include/clients.h b/src/include/clients.h index a9b66429cc..7d3288a489 100644 --- a/src/include/clients.h +++ b/src/include/clients.h @@ -26,13 +26,6 @@ * @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 diff --git a/src/include/libradius.h b/src/include/libradius.h index 3faab756b5..1b975517b5 100644 --- a/src/include/libradius.h +++ b/src/include/libradius.h @@ -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 #ifdef WITH_TCP diff --git a/src/include/radiusd.h b/src/include/radiusd.h index 36e5741158..2b9bc19f15 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -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 diff --git a/src/include/realms.h b/src/include/realms.h index 0a5132611d..171a449112 100644 --- a/src/include/realms.h +++ b/src/include/realms.h @@ -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; diff --git a/src/main/client.c b/src/main/client.c index 027839b4f6..c5330431be 100644 --- a/src/main/client.c +++ b/src/main/client.c @@ -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; } diff --git a/src/main/listen.c b/src/main/listen.c index 8f8e1146fd..2a8c7ecac5 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -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; diff --git a/src/main/mainconfig.c b/src/main/mainconfig.c index 2b1c568c33..957bff933f 100644 --- a/src/main/mainconfig.c +++ b/src/main/mainconfig.c @@ -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; diff --git a/src/main/process.c b/src/main/process.c index 251cb6b75d..9db24e31e7 100644 --- a/src/main/process.c +++ b/src/main/process.c @@ -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("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + } } /* diff --git a/src/main/realms.c b/src/main/realms.c index 991496cac0..3f2c37270c 100644 --- a/src/main/realms.c +++ b/src/main/realms.c @@ -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. */