6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2011,2012 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
30 static void cleanup(RADIUS_PACKET *packet)
33 if (packet->sockfd >= 0) close(packet->sockfd);
37 /** Copy packet to multiple servers
39 * Create a duplicate of the packet and send it to a list of realms
40 * defined by the presence of the Replicate-To-Realm VP in the control
41 * list of the current request.
43 * This is pretty hacky and is 100% fire and forget. If you're looking
44 * to forward authentication requests to multiple realms and process
45 * the responses, this function will not allow you to do that.
47 * @param[in] instance of this module.
48 * @param[in] request The current request.
49 * @param[in] list of attributes to copy to the duplicate packet.
50 * @param[in] code to write into the code field of the duplicate packet.
51 * @return RCODE fail on error, invalid if list does not exist, noop if no
52 * replications succeeded, else ok.
54 static int replicate_packet(void *instance, REQUEST *request,
55 pair_lists_t list, unsigned int code)
57 int rcode = RLM_MODULE_NOOP;
58 VALUE_PAIR *vp, **vps, *last;
62 RADIUS_PACKET *packet = NULL;
64 instance = instance; /* -Wunused */
65 last = request->config_items;
68 * Send as many packets as necessary to different
72 vp = pairfind(last, PW_REPLICATE_TO_REALM, 0);
77 realm = realm_find2(vp->vp_strvalue);
79 RDEBUG2("ERROR: Cannot Replicate to unknown realm %s", realm);
84 * We shouldn't really do this on every loop.
86 switch (request->packet->code) {
88 RDEBUG2("ERROR: Cannot replicate unknown packet code %d",
89 request->packet->code);
91 return RLM_MODULE_FAIL;
93 case PW_AUTHENTICATION_REQUEST:
94 pool = realm->auth_pool;
97 #ifdef WITH_ACCOUNTING
99 case PW_ACCOUNTING_REQUEST:
100 pool = realm->acct_pool;
106 case PW_DISCONNECT_REQUEST:
107 pool = realm->acct_pool;
113 RDEBUG2(" WARNING: Cancelling replication to Realm %s, as the realm is local.", realm->name);
117 home = home_server_ldb(realm->name, pool, request);
119 RDEBUG2("ERROR: Failed to find live home server for realm %s",
125 * For replication to multiple servers we re-use the packet
129 packet = rad_alloc(1);
130 if (!packet) return RLM_MODULE_FAIL;
133 packet->id = fr_rand() & 0xff;
135 packet->sockfd = fr_socket(&home->src_ipaddr, 0);
136 if (packet->sockfd < 0) {
137 RDEBUG("ERROR: Failed opening socket: %s", fr_strerror());
138 rcode = RLM_MODULE_FAIL;
142 vps = radius_list(request, list);
144 RDEBUG("WARNING: List '%s' doesn't exist for "
145 "this packet", fr_int2str(pair_lists,
147 rcode = RLM_MODULE_INVALID;
152 * Don't assume the list actually contains any
156 packet->vps = paircopy(*vps);
158 RDEBUG("ERROR: Out of memory!");
159 rcode = RLM_MODULE_FAIL;
167 * For CHAP, create the CHAP-Challenge if
170 if ((code == PW_AUTHENTICATION_REQUEST) &&
171 (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0) != NULL) &&
172 (pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0) == NULL)) {
173 vp = radius_paircreate(request, &packet->vps,
174 PW_CHAP_CHALLENGE, 0,
176 vp->length = AUTH_VECTOR_LEN;
177 memcpy(vp->vp_strvalue, request->packet->vector,
183 for (i = 0; i < sizeof(packet->vector); i++) {
184 packet->vector[i] = fr_rand() & 0xff;
190 packet->data_len = 0;
196 packet->dst_ipaddr = home->ipaddr;
197 packet->dst_port = home->port;
198 memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
199 packet->src_port = 0;
202 * Encode, sign and then send the packet.
204 RDEBUG("Replicating list '%s' to Realm '%s'",
205 fr_int2str(pair_lists, list, "¿unknown?"),realm->name);
206 if (rad_send(packet, NULL, home->secret) < 0) {
207 RDEBUG("ERROR: Failed replicating packet: %s",
209 rcode = RLM_MODULE_FAIL;
214 * We've sent it to at least one destination.
216 rcode = RLM_MODULE_OK;
225 static int replicate_packet(void *instance, REQUEST *request,
226 pair_lists_t list, unsigned int code)
228 RDEBUG("Replication is unsupported in this build.");
229 return RLM_MODULE_FAIL;
233 static int replicate_authorize(void *instance, REQUEST *request)
235 return replicate_packet(instance, request, PAIR_LIST_REQUEST,
236 request->packet->code);
239 static int replicate_preaccounting(void *instance, REQUEST *request)
241 return replicate_packet(instance, request, PAIR_LIST_REQUEST,
242 request->packet->code);
245 static int replicate_accounting(void *instance, REQUEST *request)
247 return replicate_packet(instance, request, PAIR_LIST_REPLY,
248 request->reply->code);
251 static int replicate_preproxy(void *instance, REQUEST *request)
253 return replicate_packet(instance, request, PAIR_LIST_PROXY_REQUEST,
254 request->proxy->code);
257 static int replicate_postproxy(void *instance, REQUEST *request)
259 return replicate_packet(instance, request, PAIR_LIST_PROXY_REPLY,
260 request->proxy_reply->code);
263 static int replicate_postauth(void *instance, REQUEST *request)
265 return replicate_packet(instance, request, PAIR_LIST_REPLY,
266 request->reply->code);
269 static int replicate_coarequest(void *instance, REQUEST *request)
271 return replicate_packet(instance, request, PAIR_LIST_REQUEST,
272 request->packet->code);
276 * The module name should be the only globally exported symbol.
277 * That is, everything else should be 'static'.
279 * If the module needs to temporarily modify it's instantiation
280 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
281 * The server will then take care of ensuring that the module
282 * is single-threaded.
284 module_t rlm_replicate = {
287 RLM_TYPE_THREAD_SAFE, /* type */
288 NULL, /* instantiation */
291 NULL, /* authentication */
292 replicate_authorize, /* authorization */
293 replicate_preaccounting,/* preaccounting */
294 replicate_accounting, /* accounting */
295 NULL, /* checksimul */
296 replicate_preproxy, /* pre-proxy */
297 replicate_postproxy, /* post-proxy */
298 replicate_postauth /* post-auth */
300 , replicate_coarequest, /* coa-request */