All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_replicate.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: deba4012d1d5a7e68d322e3389e32c67bcf06792 $
19  * @file rlm_replicate.c
20  * @brief Duplicate RADIUS requests.
21  *
22  * @copyright 2011-2013 The FreeRADIUS server project
23  */
24 RCSID("$Id: deba4012d1d5a7e68d322e3389e32c67bcf06792 $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 
29 #ifdef WITH_PROXY
30 
31 /** Allocate a request packet
32  *
33  * This is done once per request with the same packet being sent to multiple realms.
34  */
36 {
37  rlm_rcode_t rcode = RLM_MODULE_OK;
38  RADIUS_PACKET *packet = NULL;
39  VALUE_PAIR *vp, **vps;
40 
41  *out = NULL;
42 
43  packet = fr_radius_alloc(request, true);
44  if (!packet) {
45  return RLM_MODULE_FAIL;
46  }
47  packet->code = code;
48 
49  /*
50  * Figure out which list in the request were replicating
51  */
52  vps = radius_list(request, list);
53  if (!vps) {
54  RWDEBUG("List \"%s\" doesn't exist for this packet", fr_int2str(pair_lists, list, "<INVALID>"));
55  rcode = RLM_MODULE_INVALID;
56  goto error;
57  }
58 
59  /*
60  * Don't assume the list actually contains any attributes.
61  */
62  if (*vps) {
63  packet->vps = fr_pair_list_copy(packet, *vps);
64  if (!packet->vps) {
65  rcode = RLM_MODULE_FAIL;
66  goto error;
67  }
68  RDEBUG2("Will replicate attribute(s)");
69  rdebug_proto_pair_list(L_DBG_LVL_2, request, packet->vps, NULL);
70  }
71 
72  /*
73  * For CHAP, create the CHAP-Challenge if it doesn't exist.
74  */
75  if ((code == PW_CODE_ACCESS_REQUEST) &&
76  (fr_pair_find_by_num(request->packet->vps, 0, PW_CHAP_PASSWORD, TAG_ANY) != NULL) &&
77  (fr_pair_find_by_num(request->packet->vps, 0, PW_CHAP_CHALLENGE, TAG_ANY) == NULL)) {
78  vp = radius_pair_create(packet, &packet->vps, PW_CHAP_CHALLENGE, 0);
80  }
81 
82  *out = packet;
83  return rcode;
84 
85 error:
86  talloc_free(packet);
87  return rcode;
88 }
89 
90 /** Copy packet to multiple servers
91  *
92  * Create a duplicate of the packet and send it to a list of realms
93  * defined by the presence of the Replicate-To-Realm VP in the control
94  * list of the current request.
95  *
96  * This is pretty hacky and is 100% fire and forget. If you're looking
97  * to forward authentication requests to multiple realms and process
98  * the responses, this function will not allow you to do that.
99  *
100  * @param[in] instance of this module.
101  * @param[in] request The current request.
102  * @param[in] list of attributes to copy to the duplicate packet.
103  * @param[in] code to write into the code field of the duplicate packet.
104  * @return
105  * - #RLM_MODULE_FAIL on error.
106  * - #RLM_MODULE_INVALID if list does not exist.
107  * - #RLM_MODULE_NOOP if no replications succeeded.
108  * - #RLM_MODULE_OK if successful.
109  */
110 static rlm_rcode_t replicate_packet(UNUSED void *instance, REQUEST *request, pair_lists_t list, PW_CODE code)
111 {
112  int rcode;
113  bool pass1 = true;
114 
115  vp_cursor_t cursor;
116  VALUE_PAIR *vp;
117 
118  RADIUS_PACKET *packet = NULL;
119 
120  rcode = rlm_replicate_alloc(&packet, request, list, code);
121  if (rcode != RLM_MODULE_OK) return rcode;
122 
123  packet->sockfd = -1;
124 
125  /*
126  * Send as many packets as necessary to different destinations.
127  */
128  fr_cursor_init(&cursor, &request->config);
129  while ((vp = fr_cursor_next_by_num(&cursor, 0, PW_REPLICATE_TO_REALM, TAG_ANY))) {
130  home_server_t *home;
131  REALM *realm;
132  home_pool_t *pool;
133 
134  realm = realm_find2(vp->vp_strvalue);
135  if (!realm) {
136  REDEBUG2("Cannot Replicate to unknown realm \"%s\"", vp->vp_strvalue);
137  continue;
138  }
139 
140  /*
141  * We shouldn't really do this on every loop.
142  */
143  switch (request->packet->code) {
144  default:
145  REDEBUG2("Cannot replicate unknown packet code %d", request->packet->code);
146  rcode = RLM_MODULE_FAIL;
147  goto done;
148 
150  pool = realm->auth_pool;
151  break;
152 
153 #ifdef WITH_ACCOUNTING
154 
156  pool = realm->acct_pool;
157  break;
158 #endif
159 
160 #ifdef WITH_COA
161  case PW_CODE_COA_REQUEST:
163  pool = realm->coa_pool;
164  break;
165 #endif
166  }
167 
168  if (!pool) {
169  RWDEBUG2("Cancelling replication to Realm %s, as the realm is local", realm->name);
170  continue;
171  }
172 
173  home = home_server_ldb(realm->name, pool, request);
174  if (!home) {
175  REDEBUG2("Failed to find live home server for realm %s", realm->name);
176  continue;
177  }
178 
179  /*
180  * For replication to multiple servers we re-use the packet
181  * we built here.
182  */
183  if (pass1) {
184  packet->id = fr_rand() & 0xff;
185  packet->sockfd = fr_socket(&home->src_ipaddr, 0);
186  if (packet->sockfd < 0) {
187  REDEBUG("Failed opening socket: %s", fr_strerror());
188  rcode = RLM_MODULE_FAIL;
189  goto done;
190  }
191  pass1 = false;
192  } else {
193  size_t i;
194 
195  for (i = 0; i < sizeof(packet->vector); i++) {
196  packet->vector[i] = fr_rand() & 0xff;
197  }
198 
199  packet->id++;
200  TALLOC_FREE(packet->data);
201  packet->data_len = 0;
202  }
203 
204  /*
205  * (Re)-Write these.
206  */
207  packet->dst_ipaddr = home->ipaddr;
208  packet->dst_port = home->port;
209  memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
210  packet->src_port = 0;
211 
212  /*
213  * Encode, sign and then send the packet.
214  */
215  RDEBUG("Replicating %s list to Realm \"%s\"", fr_int2str(pair_lists, list, "<INVALID>"), realm->name);
216  if (fr_radius_send(packet, NULL, home->secret) < 0) {
217  REDEBUG("Failed replicating packet: %s", fr_strerror());
218  rcode = RLM_MODULE_FAIL;
219  goto done;
220  }
221 
222  /*
223  * We've sent it to at least one destination.
224  */
225  rcode = RLM_MODULE_OK;
226  }
227 
228 done:
229  if (packet) {
230  if ((packet->sockfd >= 0) && (close(packet->sockfd) < 0)) {
231  RWARN("Error closing socket (we may leak file descriptors): %s", fr_syserror(errno));
232  }
233  talloc_free(packet);
234  }
235  return rcode;
236 }
237 #else
238 static rlm_rcode_t replicate_packet(UNUSED void *instance,
239  UNUSED REQUEST *request,
240  UNUSED pair_lists_t list,
241  UNUSED unsigned int code)
242 {
243  RDEBUG("Replication is unsupported in this build");
244  return RLM_MODULE_FAIL;
245 }
246 #endif
247 
248 static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
249 {
250  return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
251 }
252 
253 static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
254 {
255  return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
256 }
257 
258 static rlm_rcode_t CC_HINT(nonnull) mod_preaccounting(void *instance, REQUEST *request)
259 {
260  return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
261 }
262 
263 #ifdef WITH_PROXY
264 static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
265 {
266  return replicate_packet(instance, request, PAIR_LIST_PROXY_REQUEST, request->proxy->code);
267 }
268 #endif
269 
270 #ifdef WITH_COA
271 static rlm_rcode_t CC_HINT(nonnull) mod_recv_coa(void *instance, REQUEST *request)
272 {
273  return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
274 }
275 #endif
276 
277 /*
278  * The module name should be the only globally exported symbol.
279  * That is, everything else should be 'static'.
280  *
281  * If the module needs to temporarily modify it's instantiation
282  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
283  * The server will then take care of ensuring that the module
284  * is single-threaded.
285  */
286 extern module_t rlm_replicate;
287 module_t rlm_replicate = {
289  .name = "replicate",
290  .type = RLM_TYPE_THREAD_SAFE,
291  .methods = {
294  [MOD_PREACCT] = mod_preaccounting,
295 #ifdef WITH_PROXY
296  [MOD_PRE_PROXY] = mod_pre_proxy,
297 #endif
298 #ifdef WITH_COA
299  [MOD_RECV_COA] = mod_recv_coa
300 #endif
301  },
302 };
5 methods index for preproxy section.
Definition: modules.h:46
REALM * realm_find2(char const *name)
Definition: realms.c:2201
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
2nd highest priority debug messages (-xx | -X).
Definition: log.h:52
fr_ipaddr_t src_ipaddr
Resolved version of src_ipaddr_str.
Definition: realms.h:87
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
Write accounting data to Couchbase documents.
The module is OK, continue.
Definition: radiusd.h:91
Metadata exported by the module.
Definition: modules.h:134
VALUE_PAIR * fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int vendor, unsigned int attr, int8_t tag)
Iterate over a collection of VALUE_PAIRs of a given type in the pairlist.
Definition: cursor.c:200
module_t rlm_replicate
#define RWARN(fmt,...)
Definition: log.h:206
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
VALUE_PAIR ** radius_list(REQUEST *request, pair_lists_t list)
Resolve attribute pair_lists_t value to an attribute list.
Definition: tmpl.c:195
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
Handle authorization requests using Couchbase document data.
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: modules.h:75
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
#define REDEBUG2(fmt,...)
Definition: log.h:255
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
int fr_radius_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret)
Reply to the request.
Definition: radius.c:506
home_pool_t * auth_pool
Definition: realms.h:183
Definition: realms.h:178
A copy of attributes in the request list that may be modified in pre-proxy before proxying the reques...
Definition: tmpl.h:90
The module considers the request invalid.
Definition: radiusd.h:93
uint8_t * data
Packet data (body).
Definition: libradius.h:160
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
pair_lists
Definition: tmpl.h:80
RFC2865 - Access-Request.
Definition: radius.h:92
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
Definition: pair.c:1394
static rlm_rcode_t replicate_packet(UNUSED void *instance, REQUEST *request, pair_lists_t list, PW_CODE code)
Copy packet to multiple servers.
home_server_t * home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request)
Definition: realms.c:2352
#define AUTH_VECTOR_LEN
Definition: libradius.h:118
home_pool_t * coa_pool
Definition: realms.h:186
RFC2866 - Accounting-Request.
Definition: radius.h:95
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
static bool done
Definition: radclient.c:53
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
unsigned int code
Packet code (type).
Definition: libradius.h:155
3 methods index for accounting section.
Definition: modules.h:44
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
RFC3575/RFC5176 - CoA-Request.
Definition: radius.h:108
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
#define RWDEBUG2(fmt,...)
Definition: log.h:252
#define RDEBUG2(fmt,...)
Definition: log.h:244
void rdebug_proto_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of protocol VALUE_PAIRs.
Definition: pair.c:784
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
#define TAG_ANY
Definition: pair.h:191
int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
Definition: packet.c:136
char const * name
Definition: realms.h:179
size_t data_len
Length of packet data.
Definition: libradius.h:161
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
enum pair_lists pair_lists_t
#define REDEBUG(fmt,...)
Definition: log.h:254
2 methods index for preacct section.
Definition: modules.h:43
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
8 methods index for recvcoa section.
Definition: modules.h:50
PW_CODE
RADIUS packet codes.
Definition: radius.h:90
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
home_pool_t * acct_pool
Definition: realms.h:184
#define RWDEBUG(fmt,...)
Definition: log.h:251
1 methods index for authorize section.
Definition: modules.h:42
static rlm_rcode_t rlm_replicate_alloc(RADIUS_PACKET **out, REQUEST *request, pair_lists_t list, PW_CODE code)
Allocate a request packet.
Definition: rlm_replicate.c:35
#define RCSID(id)
Definition: build.h:135
char const * secret
Definition: realms.h:95
uint16_t port
Definition: realms.h:79
#define RDEBUG(fmt,...)
Definition: log.h:243
fr_ipaddr_t ipaddr
IP address of home server.
Definition: realms.h:78
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
RFC3575/RFC5176 - Disconnect-Request.
Definition: radius.h:105
static rlm_rcode_t CC_HINT(nonnull)