#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
static void cleanup(RADIUS_PACKET *packet)
{
if (!packet) return;
if (packet->sockfd >= 0) close(packet->sockfd);
rad_free(&packet);
}
static int replicate_packet(void *instance, REQUEST *request)
{
int rcode = RLM_MODULE_NOOP;
VALUE_PAIR *vp, *last;
home_server *home;
REALM *realm;
home_pool_t *pool;
RADIUS_PACKET *packet = NULL;
instance = instance;
last = request->config_items;
while (1) {
vp = pairfind(last, PW_REPLICATE_TO_REALM);
if (!vp) break;
last = vp->next;
realm = realm_find2(vp->vp_strvalue);
if (!realm) {
RDEBUG2("ERROR: Cannot Replicate to unknown realm %s", realm);
continue;
}
switch (request->packet->code) {
default:
RDEBUG2("ERROR: Cannot replicate unknown packet code %d",
request->packet->code);
cleanup(packet);
return RLM_MODULE_FAIL;
case PW_AUTHENTICATION_REQUEST:
pool = realm->auth_pool;
break;
#ifdef WITH_ACCOUNTING
case PW_ACCOUNTING_REQUEST:
pool = realm->acct_pool;
break;
#endif
#ifdef WITH_COA
case PW_COA_REQUEST:
case PW_DISCONNECT_REQUEST:
pool = realm->acct_pool;
break;
#endif
}
if (!pool) {
RDEBUG2(" WARNING: Cancelling replication to Realm %s, as the realm is local.", realm->name);
continue;
}
home = home_server_ldb(realm->name, pool, request);
if (!home) {
RDEBUG2("ERROR: Failed to find live home server for realm %s",
realm->name);
continue;
}
if (!packet) {
packet = rad_alloc(1);
if (!packet) return RLM_MODULE_FAIL;
packet->sockfd = -1;
packet->code = request->packet->code;
packet->id = fr_rand() & 0xff;
packet->sockfd = fr_socket(&home->src_ipaddr, 0);
if (packet->sockfd < 0) {
RDEBUG("ERROR: Failed opening socket: %s", fr_strerror());
cleanup(packet);
return RLM_MODULE_FAIL;
}
packet->vps = paircopy(request->packet->vps);
if (!packet->vps) {
RDEBUG("ERROR: Out of memory!");
cleanup(packet);
return RLM_MODULE_FAIL;
}
if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
(pairfind(request->packet->vps, PW_CHAP_PASSWORD) != NULL) &&
(pairfind(request->packet->vps, PW_CHAP_CHALLENGE) == NULL)) {
vp = radius_paircreate(request, &packet->vps,
PW_CHAP_CHALLENGE,
PW_TYPE_OCTETS);
vp->length = AUTH_VECTOR_LEN;
memcpy(vp->vp_strvalue, request->packet->vector,
AUTH_VECTOR_LEN);
}
} else {
size_t i;
for (i = 0; i < sizeof(packet->vector); i++) {
packet->vector[i] = fr_rand() & 0xff;
}
packet->id++;
free(packet->data);
packet->data = NULL;
packet->data_len = 0;
}
packet->dst_ipaddr = home->ipaddr;
packet->dst_port = home->port;
memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
packet->src_port = 0;
RDEBUG("Replicating packet to Realm %s", realm->name);
if (rad_send(packet, NULL, home->secret) < 0) {
RDEBUG("ERROR: Failed replicating packet: %s",
fr_strerror());
cleanup(packet);
return RLM_MODULE_FAIL;
}
rcode = RLM_MODULE_OK;
}
cleanup(packet);
return rcode;
}
module_t rlm_replicate = {
RLM_MODULE_INIT,
"replicate",
RLM_TYPE_THREAD_SAFE,
NULL,
NULL,
{
NULL,
replicate_packet,
NULL,
replicate_packet,
NULL,
NULL,
NULL,
NULL
#ifdef WITH_COA
, replicate_packet,
NULL
#endif
},
};