summaryrefslogtreecommitdiffstats
path: root/src/main/process.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/main/process.c189
1 files changed, 149 insertions, 40 deletions
diff --git a/src/main/process.c b/src/main/process.c
index ed77839..9880e34 100644
--- a/src/main/process.c
+++ b/src/main/process.c
@@ -1006,6 +1006,12 @@ static void request_cleanup_delay_init(REQUEST *request)
#ifdef HAVE_PTHREAD_H
rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
#endif
+
+ /*
+ * Set the statistics immediately if we can.
+ */
+ request_stats_final(request);
+
STATE_MACHINE_TIMER(FR_ACTION_TIMER);
return;
}
@@ -1258,6 +1264,9 @@ static void request_cleanup_delay(REQUEST *request, int action)
#ifdef DEBUG_STATE_MACHINE
if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
#endif
+
+ request_stats_final(request);
+
STATE_MACHINE_TIMER(FR_ACTION_TIMER);
return;
} /* else it's time to clean up */
@@ -1486,7 +1495,7 @@ static void request_finish(REQUEST *request, int action)
/*
* Maybe originate a CoA request.
*/
- if ((action == FR_ACTION_RUN) && !request->proxy && request->coa) {
+ if ((action == FR_ACTION_RUN) && (!request->proxy || request->proxy->dst_port == 0) && request->coa) {
request_coa_originate(request);
}
#endif
@@ -1591,9 +1600,14 @@ static void request_finish(REQUEST *request, int action)
#ifdef WITH_PROXY
/*
* If we timed out a proxy packet, don't delay
- * the reject any more.
+ * the reject any more. Or, if we proxied it to
+ * a real home server, then don't delay it.
+ *
+ * We don't want to have each proxy in a chain
+ * adding their own reject delay, which would
+ * result in N*reject_delays being applied.
*/
- if (request->proxy && !request->proxy_reply) {
+ if (request->proxy && (!request->proxy_reply || request->proxy->dst_port != 0)) {
request->response_delay.tv_sec = 0;
request->response_delay.tv_usec = 0;
}
@@ -2024,6 +2038,10 @@ static REQUEST *request_setup(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PA
return NULL;
}
+#ifdef WITH_RADIUSV11
+ request->reply->radiusv11 = packet->radiusv11;
+#endif
+
request->listener = listener;
request->client = client;
request->packet = talloc_steal(request, packet);
@@ -2286,16 +2304,6 @@ static void remove_from_proxy_hash_nl(REQUEST *request, bool yank)
if (!request->in_proxy_hash) return;
-#ifdef COA_TUNNEL
- /*
- * Track how many IDs are used. This information
- * helps the listen_coa_find() function get a
- * listener which has free IDs.
- */
- rad_assert(request->proxy_listener->num_ids_used > 0);
- request->proxy_listener->num_ids_used--;
-#endif
-
fr_packet_list_id_free(proxy_list, request->proxy, yank);
request->in_proxy_hash = false;
@@ -2341,6 +2349,18 @@ static void remove_from_proxy_hash_nl(REQUEST *request, bool yank)
if (request->proxy_listener) {
request->proxy_listener->count--;
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Track how many IDs are used. This information
+ * helps the listen_coa_find() function get a
+ * listener which has free IDs.
+ */
+ if (request->proxy_listener->send_coa) {
+ rad_assert(request->proxy_listener->num_ids_used > 0);
+ request->proxy_listener->num_ids_used--;
+ }
+#endif
}
request->proxy_listener = NULL;
@@ -2361,18 +2381,6 @@ static void remove_from_proxy_hash(REQUEST *request)
*/
if (!request->in_proxy_hash) return;
-#ifdef WITH_TCP
- /*
- * Status-Server packets aren't removed from the proxy hash. They're reused.
- *
- * Unless we're tearing down the listener.
- */
- if ((request->proxy->proto == IPPROTO_TCP) && (request->proxy->code == PW_CODE_STATUS_SERVER) &&
- request->proxy_listener && (request->proxy_listener->status < RAD_LISTEN_STATUS_EOL)) {
- return;
- }
-#endif
-
/*
* The "not in hash" flag is definitive. However, if the
* flag says that it IS in the hash, there might still be
@@ -2493,13 +2501,13 @@ static int insert_into_proxy_hash(REQUEST *request)
goto fail;
}
-#ifdef COA_TUNNEL
+#ifdef WITH_COA_TUNNEL
/*
* Track how many IDs are used. This information
* helps the listen_coa_find() function get a
* listener which has free IDs.
*/
- request->proxy_listener->num_ids_used++;
+ if (request->proxy_listener->send_coa) request->proxy_listener->num_ids_used++;
#endif
/*
@@ -2790,16 +2798,78 @@ int request_proxy_reply(RADIUS_PACKET *packet)
* server core, but I guess we can fix that later.
*/
if (!request->proxy_reply) {
+ decode_fail_t reason;
+
+ /*
+ * If the home server configuration requires a Message-Authenticator, then set the flag,
+ * but only if the proxied packet is Access-Request or Status-Sercer.
+ *
+ * The realms.c file already clears require_ma for TLS connections.
+ */
+ 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);
return 0;
}
+ if (!rad_packet_ok(packet, require_ma, &reason)) {
+ DEBUG("Ignoring invalid packet - %s", fr_strerror());
+ return 0;
+ }
+
if (rad_verify(packet, request->proxy,
request->home_server->secret) != 0) {
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 home_server %s.", request->home_server->name);
+ 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 updated to protect from the BlastRADIUS attack.");
+ RERROR("Please set \"require_message_authenticator = true\" for home_server %s", request->home_server->name);
+ 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 home_server %s", request->home_server->name);
+ RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ }
+ }
}
/*
@@ -2863,6 +2933,18 @@ int request_proxy_reply(RADIUS_PACKET *packet)
#ifdef WITH_STATS
/*
+ * The average includes our time to receive packets and
+ * look them up in the hashes, which should be the same
+ * for all packets.
+ *
+ * We update the response time only for the FIRST packet
+ * we receive.
+ */
+ if (request->home_server->ema.window > 0) {
+ radius_stats_ema(&request->home_server->ema, &request->proxy->timestamp, &now);
+ }
+
+ /*
* Update the proxy listener stats here, because only one
* thread accesses that at a time. The home_server and
* main proxy_*_stats structures are updated once the
@@ -3193,6 +3275,14 @@ static int request_will_proxy(REQUEST *request)
pool = home_pool_byname(vp->vp_strvalue, pool_type);
/*
+ * If we didn't find an auth only or acct only pool
+ * fall-back to those which do both.
+ */
+ if (!pool && ((pool_type == HOME_TYPE_AUTH) || (pool_type == HOME_TYPE_ACCT))) {
+ pool = home_pool_byname(vp->vp_strvalue, HOME_TYPE_AUTH_ACCT);
+ }
+
+ /*
* Send it directly to a home server (i.e. NAS)
*/
} else if (((vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY)) != NULL) ||
@@ -3292,6 +3382,15 @@ static int request_will_proxy(REQUEST *request)
* Find the home server by name.
*/
home = home_server_byname(vp->vp_strvalue, type);
+
+ /*
+ * If we didn't find an auth only or acct only home server
+ * fall-back to those which do both.
+ */
+ if (!home && ((type == HOME_TYPE_AUTH) || (type == HOME_TYPE_ACCT))) {
+ home = home_server_byname(vp->vp_strvalue, HOME_TYPE_AUTH_ACCT);
+ }
+
if (!home) {
RWDEBUG("No such home server %s", vp->vp_strvalue);
return 0;
@@ -3361,7 +3460,7 @@ static int request_will_proxy(REQUEST *request)
home = home_server_ldb(realmname, pool, request);
if (!home) {
- REDEBUG2("Failed to find live home server: Cancelling proxy");
+ REDEBUG2("Failed to find live home server for realm %s: Cancelling proxy", realmname);
return -1;
}
@@ -3373,7 +3472,11 @@ do_home:
* Once we've decided to proxy a request, we cannot send
* a CoA packet. So we free up any CoA packet here.
*/
- if (request->coa) request_done(request->coa, FR_ACTION_COA_CANCELLED);
+ if (request->coa) {
+ RWDEBUG("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request");
+ request_done(request->coa, FR_ACTION_COA_CANCELLED);
+ request->coa = NULL;
+ }
#endif
/*
@@ -3605,6 +3708,7 @@ static int request_proxy(REQUEST *request)
if (request->coa) {
RWDEBUG("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request");
request_done(request->coa, FR_ACTION_COA_CANCELLED);
+ request->coa = NULL;
}
#endif
@@ -3817,6 +3921,7 @@ static void request_ping(REQUEST *request, int action)
break;
case FR_ACTION_PROXY_REPLY:
+ default:
rad_assert(request->in_proxy_hash);
request->home_server->num_received_pings++;
@@ -3855,9 +3960,10 @@ static void request_ping(REQUEST *request, int action)
mark_home_server_alive(request, home);
break;
- default:
+ case FR_ACTION_RUN:
+ case FR_ACTION_DUP:
RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
- break;
+ return;
}
rad_assert(!request->in_request_hash);
@@ -4339,10 +4445,10 @@ static void proxy_wait_for_reply(REQUEST *request, int action)
* and should be suppressed by the proxy.
*/
when = request->proxy->timestamp;
- when.tv_sec++;
+ when.tv_sec += main_config.proxy_dedup_window;
if (timercmp(&now, &when, <)) {
- DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d proto TCP - ID: %d",
+ DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d - ID: %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
@@ -4543,9 +4649,9 @@ static void request_coa_originate(REQUEST *request)
VERIFY_REQUEST(request);
rad_assert(request->coa != NULL);
- rad_assert(request->proxy == NULL);
+ rad_assert(request->proxy == NULL || request->proxy->dst_port == 0);
rad_assert(!request->in_proxy_hash);
- rad_assert(request->proxy_reply == NULL);
+ rad_assert(request->proxy_reply == NULL || request->proxy_reply->src_port == 0);
/*
* Check whether we want to originate one, or cancel one.
@@ -5018,7 +5124,11 @@ static bool coa_max_time(REQUEST *request)
buffer, sizeof(buffer)),
request->proxy->dst_port,
mrd);
- request_done(request, FR_ACTION_DONE);
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, coa_no_reply);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
return true;
}
@@ -5386,7 +5496,6 @@ static void listener_free_cb(void *ctx)
talloc_free(this);
}
-#ifdef WITH_TCP
#ifdef WITH_PROXY
static int proxy_eol_cb(void *ctx, void *data)
{
@@ -5426,7 +5535,6 @@ static int proxy_eol_cb(void *ctx, void *data)
return 0;
}
#endif /* WITH_PROXY */
-#endif /* WITH_TCP */
static void event_new_fd(rad_listen_t *this)
{
@@ -5602,6 +5710,7 @@ static void event_new_fd(rad_listen_t *this)
*/
this->print(this, buffer, sizeof(buffer));
ERROR("Failed adding event handler for socket %s: %s", buffer, fr_strerror());
+
this->status = RAD_LISTEN_STATUS_EOL;
goto listener_is_eol;
} /* end of INIT */
@@ -5645,6 +5754,7 @@ static void event_new_fd(rad_listen_t *this)
fr_event_fd_delete(el, 0, this->fd);
this->status = RAD_LISTEN_STATUS_REMOVE_NOW;
}
+#endif /* WITH_TCP */
/*
* The socket has had a catastrophic error. Close it.
@@ -5708,7 +5818,6 @@ static void event_new_fd(rad_listen_t *this)
*/
this->status = RAD_LISTEN_STATUS_REMOVE_NOW;
} /* socket is at EOL */
-#endif /* WITH_TCP */
if (this->dead) goto wait_some_more;
@@ -6147,7 +6256,7 @@ static void check_proxy(rad_listen_t *head)
if (sock->my_ipaddr.af == AF_INET) has_v4 = true;
if (sock->my_ipaddr.af == AF_INET6) has_v6 = true;
break;
-
+
default:
break;
}