All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
request.c
Go to the documentation of this file.
1 /*
2  * This program 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
5  * (at 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: f3ad970d90a7c95cbcb1aeb6676ee8896392d187 $
19  *
20  * @brief Functions for allocating requests and storing internal data in them.
21  * @file main/request.c
22  *
23  * @copyright 2015 The FreeRADIUS server project
24  */
25 RCSID("$Id: f3ad970d90a7c95cbcb1aeb6676ee8896392d187 $")
26 
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
29 
30 /** Per-request opaque data, added by modules
31  *
32  */
34  request_data_t *next; //!< Next opaque request data struct linked to this request.
35 
36  void *unique_ptr; //!< Key to lookup request data.
37  int unique_int; //!< Alternative key to lookup request data.
38  void *opaque; //!< Opaque data.
39  bool free_on_replace; //!< Whether to talloc_free(opaque) when the request data is removed.
40  bool free_on_parent; //!< Whether to talloc_free(opaque) when the parent of the request
41  //!< data is freed.
42  bool persist; //!< Whether this data should be transfered to a session_entry_t
43  //!< after we're done processing this request.
44 };
45 
46 /** Callback for freeing a request struct
47  *
48  */
49 static int _request_free(REQUEST *request)
50 {
51  rad_assert(!request->in_request_hash);
52 #ifdef WITH_PROXY
53  rad_assert(!request->in_proxy_hash);
54 #endif
55  rad_assert(!request->ev);
56 
57 #ifdef WITH_COA
58  rad_assert(request->coa == NULL);
59 #endif
60 
61 #ifndef NDEBUG
62  request->magic = 0x01020304; /* set the request to be nonsense */
63 #endif
64  request->client = NULL;
65 #ifdef WITH_PROXY
66  request->home_server = NULL;
67 #endif
68 
69  /*
70  * This is parented separately.
71  *
72  * The reason why it's OK to do this, is if the state attributes
73  * need to persist across requests, they will already have been
74  * moved to a fr_state_entry_t, with the state pointers in the
75  * request being set to NULL, before the request is freed.
76  */
77  if (request->state_ctx) talloc_free(request->state_ctx);
78 
79  return 0;
80 }
81 
82 /** Create a new REQUEST data structure
83  *
84  */
85 REQUEST *request_alloc(TALLOC_CTX *ctx)
86 {
87  REQUEST *request;
88 
89  request = talloc_zero(ctx, REQUEST);
90  if (!request) return NULL;
91  talloc_set_destructor(request, _request_free);
92 #ifndef NDEBUG
93  request->magic = REQUEST_MAGIC;
94 #endif
95 #ifdef WITH_PROXY
96  request->proxy = NULL;
97 #endif
98  request->reply = NULL;
99 #ifdef WITH_PROXY
100  request->proxy_reply = NULL;
101 #endif
102  request->config = NULL;
103  request->username = NULL;
104  request->password = NULL;
105  gettimeofday(&request->timestamp, NULL);
106  request->log.lvl = rad_debug_lvl; /* Default to global debug level */
107 
108  request->module = "";
109  request->component = "<core>";
110  request->log.func = vradlog_request;
111 
112  request->state_ctx = talloc_init("session-state");
113 
114  return request;
115 }
116 
117 
118 /*
119  * Create a new REQUEST, based on an old one.
120  *
121  * This function allows modules to inject fake requests
122  * into the server, for tunneled protocols like TTLS & PEAP.
123  */
125 {
126  REQUEST *fake;
127 
128  fake = request_alloc(request);
129  if (!fake) return NULL;
130 
131  fake->number = request->number;
132 #ifdef HAVE_PTHREAD_H
133  fake->child_pid = request->child_pid;
134 #endif
135  fake->parent = request;
136  fake->root = request->root;
137  fake->client = request->client;
138 
139  /*
140  * For new server support.
141  *
142  * FIXME: Key instead off of a "virtual server" data structure.
143  *
144  * FIXME: Permit different servers for inner && outer sessions?
145  */
146  fake->server = request->server;
147 
148  fake->packet = fr_radius_alloc(fake, true);
149  if (!fake->packet) {
150  talloc_free(fake);
151  return NULL;
152  }
153 
154  fake->reply = fr_radius_alloc(fake, false);
155  if (!fake->reply) {
156  talloc_free(fake);
157  return NULL;
158  }
159 
162 
163  /*
164  * Fill in the fake request.
165  */
166  fake->packet->sockfd = -1;
167  fake->packet->src_ipaddr = request->packet->src_ipaddr;
168  fake->packet->src_port = request->packet->src_port;
169  fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
170  fake->packet->dst_port = 0;
171 
172  /*
173  * This isn't STRICTLY required, as the fake request MUST NEVER
174  * be put into the request list. However, it's still reasonable
175  * practice.
176  */
177  fake->packet->id = fake->number & 0xff;
178  fake->packet->code = request->packet->code;
179  fake->timestamp = request->timestamp;
180  fake->packet->timestamp = request->packet->timestamp;
181 
182  /*
183  * Required for new identity support
184  */
185  fake->listener = request->listener;
186 
187  /*
188  * Fill in the fake reply, based on the fake request.
189  */
190  fake->reply->sockfd = fake->packet->sockfd;
191  fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
192  fake->reply->src_port = fake->packet->dst_port;
193  fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
194  fake->reply->dst_port = fake->packet->src_port;
195  fake->reply->id = fake->packet->id;
196  fake->reply->code = 0; /* UNKNOWN code */
197 
198  /*
199  * Copy debug information.
200  */
201  memcpy(&(fake->log), &(request->log), sizeof(fake->log));
202  fake->log.indent = 0; /* Apart from the indent which we reset */
203 
204  return fake;
205 }
206 
207 #ifdef WITH_COA
209 {
210  if (!request || request->coa) return NULL;
211 
212  /*
213  * Originate CoA requests only when necessary.
214  */
215  if ((request->packet->code != PW_CODE_ACCESS_REQUEST) &&
216  (request->packet->code != PW_CODE_ACCOUNTING_REQUEST)) return NULL;
217 
218  request->coa = request_alloc_fake(request);
219  if (!request->coa) return NULL;
220 
221  request->coa->options = RAD_REQUEST_OPTION_COA; /* is a CoA packet */
222  request->coa->packet->code = 0; /* unknown, as of yet */
223  request->coa->child_state = REQUEST_RUNNING;
224  request->coa->proxy = fr_radius_alloc(request->coa, false);
225  if (!request->coa->proxy) {
226  TALLOC_FREE(request->coa);
227  return NULL;
228  }
229 
230  return request->coa;
231 }
232 #endif
233 
234 /** Ensure opaque data is freed by binding its lifetime to the request_data_t
235  *
236  * @param this Request data being freed.
237  * @return 0, or whatever the destructor for the opaque data returned.
238  */
240 {
241  if (this->free_on_parent && this->opaque) {
242  int ret;
243 
244  DEBUG4("Freeing request data %p (%s) at %p:%i via destructor",
245  this->opaque, talloc_get_name(this->opaque), this->unique_ptr, this->unique_int);
246  ret = talloc_free(this->opaque);
247  this->opaque = NULL;
248 
249  return ret;
250  }
251  return 0;
252 }
253 
254 /** Add opaque data to a REQUEST
255  *
256  * The unique ptr is meant to be a module configuration, and the unique
257  * integer allows the caller to have multiple opaque data associated with a REQUEST.
258  *
259  * @param[in] request to associate data with.
260  * @param[in] unique_ptr Identifier for the data.
261  * @param[in] unique_int Qualifier for the identifier.
262  * @param[in] opaque Data to associate with the request
263  * @param[in] free_on_replace If true and the opaque data is replaced via a subsequent call
264  * to #request_data_add, talloc_free will be called to free the
265  * opaque data pointer.
266  * @param[in] free_on_parent If True and the request data is present in the request
267  * or state when it is freed, free the opaque data too.
268  * Must not be set if the opaque
269  * data is also parented by the request or state.
270  * @param[in] persist If true, before the request is freed, the opaque data will be
271  * transferred to an #fr_state_entry_t, and restored to a
272  * subsequent linked request
273  * should we receive one.
274  * @return
275  * - -2 on bad arguments.
276  * - -1 on memory allocation error.
277  * - 0 on success.
278  */
279 int request_data_add(REQUEST *request, void *unique_ptr, int unique_int, void *opaque,
280  bool free_on_replace, bool free_on_parent, bool persist)
281 {
282  request_data_t *this, **last, *next;
283 
284  /*
285  * Request must have a state ctx
286  */
287  rad_assert(!persist || request->state_ctx);
288  rad_assert(request);
289 
290  this = next = NULL;
291  for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
292 #ifdef WITH_VERIFY_PTR
293  *last = talloc_get_type_abort(*last, request_data_t);
294 #endif
295  if (((*last)->unique_ptr == unique_ptr) && ((*last)->unique_int == unique_int)) {
296  this = *last;
297  next = this->next;
298 
299  /*
300  * If caller requires custom behaviour on free
301  * they must set a destructor.
302  */
303  if (this->free_on_replace && this->opaque) {
304  RDEBUG4("Freeing request data %p at %p:%i via replacement",
305  this->opaque, this->unique_ptr, this->unique_int);
306  talloc_free(this->opaque);
307  }
308  /*
309  * Need a new one, this one's parent is wrong.
310  * And no, we can't just steal.
311  */
312  if (this->persist != persist) {
313  this->free_on_parent = false;
314  TALLOC_FREE(this);
315  }
316 
317  break; /* replace the existing entry */
318  }
319  if (!*last) break;
320  }
321 
322  /*
323  * Only alloc new memory if we're not replacing
324  * an existing entry.
325  *
326  * Tie the lifecycle of the data to either the state_ctx
327  * or the request, depending on whether it should
328  * persist or not.
329  */
330  if (!this) {
331  if (persist) {
332  rad_assert(request->state_ctx);
333  this = talloc_zero(request->state_ctx, request_data_t);
334  } else {
335  this = talloc_zero(request, request_data_t);
336  }
337  talloc_set_destructor(this, _request_data_free);
338  }
339  if (!this) return -1;
340 
341  this->next = next;
342  this->unique_ptr = unique_ptr;
343  this->unique_int = unique_int;
344  this->opaque = opaque;
345  this->free_on_replace = free_on_replace;
346  this->free_on_parent = free_on_parent;
347  this->persist = persist;
348 
349  /*
350  * Some basic protection against what might be a
351  * common pitfall.
352  */
353  rad_assert(!free_on_parent || (talloc_parent(this) != talloc_parent(opaque)));
354 
355  *last = this;
356 
357  RDEBUG4("Added request data %p at %p:%i", this->opaque, this->unique_ptr, this->unique_int);
358 
359  return 0;
360 }
361 
362 /** Get opaque data from a request
363  *
364  * @note The unique ptr is meant to be a module configuration, and the unique
365  * integer allows the caller to have multiple opaque data associated with a REQUEST.
366  *
367  * @param[in] request to retrieve data from.
368  * @param[in] unique_ptr Identifier for the data.
369  * @param[in] unique_int Qualifier for the identifier.
370  * @return
371  * - NULL if no opaque data could be found.
372  * - the opaque data. The entry holding the opaque data is removed from the request.
373  */
374 void *request_data_get(REQUEST *request, void *unique_ptr, int unique_int)
375 {
376  request_data_t **last;
377 
378  if (!request) return NULL;
379 
380  for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
381 #ifdef WITH_VERIFY_PTR
382  *last = talloc_get_type_abort(*last, request_data_t);
383 #endif
384  if (((*last)->unique_ptr == unique_ptr) && ((*last)->unique_int == unique_int)) {
385  request_data_t *this;
386  void *ptr;
387 
388  this = *last;
389  ptr = this->opaque;
390 
391  /*
392  * Remove the entry from the list, and free it.
393  */
394  *last = this->next;
395  this->free_on_parent = false; /* Don't free opaque data we're handing back */
396  talloc_free(this);
397 
398  return ptr;
399  }
400  if (!*last) break;
401  }
402 
403  return NULL; /* wasn't found, too bad... */
404 }
405 
406 /** Loop over all the request data, pulling out ones matching persist state
407  *
408  * @param[out] out Head of result list.
409  * @param[in] request to search for request_data_t in.
410  * @param[in] persist Whether to pull persistable or non-persistable data.
411  * @return number of request_data_t retrieved.
412  */
413 int request_data_by_persistance(request_data_t **out, REQUEST *request, bool persist)
414 {
415  int count = 0;
416 
417  request_data_t **last, *head = NULL, **next;
418 
419  next = &head;
420 
421  for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
422 #ifdef WITH_VERIFY_PTR
423  *last = talloc_get_type_abort(*last, request_data_t);
424 #endif
425  if ((*last)->persist == persist) {
426  request_data_t *this;
427 
428  /* Unlink it from the list */
429  this = *last;
430  *last = this->next;
431 
432  /* Add it to our list of data to return */
433  this->next = NULL;
434  *next = this;
435  next = &this->next;
436  count++;
437  }
438  if (!*last) break;
439  }
440  *out = head;
441 
442  return count;
443 }
444 
445 /** Add request data back to a request
446  *
447  * @note May add multiple entries (if they're linked).
448  * @note Will not check for duplicates.
449  *
450  * @param request to add data to.
451  * @param entry the data to add.
452  */
454 {
455  request_data_t **last;
456 
457  /*
458  * Wind to the end of the current request data
459  */
460  for (last = &(request->data); *last != NULL; last = &((*last)->next)) if (!(*last)->next) break;
461  *last = entry;
462 
463 #ifdef WITH_VERIFY_PTR
464  {
465  request_data_t *this;
466 
467  for (this = request->data; this; this = this->next) this = talloc_get_type_abort(this, request_data_t);
468  }
469 #endif
470 }
471 
472 /** Get opaque data from a request without removing it
473  *
474  * @note The unique ptr is meant to be a module configuration, and the unique
475  * integer allows the caller to have multiple opaque data associated with a REQUEST.
476  *
477  * @param request to retrieve data from.
478  * @param unique_ptr Identifier for the data.
479  * @param unique_int Qualifier for the identifier.
480  * @return
481  * - NULL if no opaque data could be found.
482  * - the opaque data.
483  */
484 void *request_data_reference(REQUEST *request, void *unique_ptr, int unique_int)
485 {
486  request_data_t **last;
487 
488  for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
489  if (((*last)->unique_ptr == unique_ptr) &&
490  ((*last)->unique_int == unique_int)) return (*last)->opaque;
491  }
492 
493  return NULL; /* wasn't found, too bad... */
494 }
495 
496 #ifdef WITH_VERIFY_PTR
497 /** Verify all request data is parented by the specified context
498  *
499  * @note Only available if built with WITH_VERIFY_PTR
500  *
501  * @param parent that should hold the request data.
502  * @param entry to verify.
503  * @return
504  * - true if chunk lineage is correct.
505  * - false if one of the chunks is parented by something else.
506  */
507 bool request_data_verify_parent(TALLOC_CTX *parent, request_data_t *entry)
508 {
509  request_data_t **last;
510 
511  for (last = &entry; *last != NULL; last = &((*last)->next)) if (talloc_parent(entry) != parent) return false;
512  return true;
513 }
514 #endif
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
bool in_request_hash
Definition: radiusd.h:278
rad_master_state_t master_state
Set by the master thread to signal the child that's currently working with the request, to do something.
Definition: radiusd.h:259
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 request_data_add(REQUEST *request, void *unique_ptr, int unique_int, void *opaque, bool free_on_replace, bool free_on_parent, bool persist)
Add opaque data to a REQUEST.
Definition: request.c:279
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
int request_data_by_persistance(request_data_t **out, REQUEST *request, bool persist)
Loop over all the request data, pulling out ones matching persist state.
Definition: request.c:413
static int _request_data_free(request_data_t *this)
Ensure opaque data is freed by binding its lifetime to the request_data_t.
Definition: request.c:239
RADIUS_PACKET * proxy_reply
Incoming response from proxy server.
Definition: radiusd.h:238
struct rad_request::@7 log
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
fr_event_t * ev
Event in event loop tied to this request.
Definition: radiusd.h:248
VALUE_PAIR * username
Cached username VALUE_PAIR from request RADIUS_PACKET.
Definition: radiusd.h:222
REQUEST * request_alloc(TALLOC_CTX *ctx)
Create a new REQUEST data structure.
Definition: request.c:85
bool free_on_replace
Whether to talloc_free(opaque) when the request data is removed.
Definition: request.c:39
VALUE_PAIR * password
Cached password VALUE_PAIR from request RADIUS_PACKET.
Definition: radiusd.h:223
rad_listen_t * listener
The listener that received the request.
Definition: radiusd.h:218
unsigned int number
Monotonically increasing request number. Reset on server restart.
Definition: radiusd.h:213
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
REQUEST * request_alloc_coa(REQUEST *request)
Definition: request.c:208
bool persist
Whether this data should be transfered to a session_entry_t after we're done processing this request...
Definition: request.c:42
REQUEST * request_alloc_fake(REQUEST *request)
Definition: request.c:124
void vradlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap) CC_HINT(format(printf
uint32_t magic
Magic number used to detect memory corruption, or request structs that have not been properly initial...
Definition: radiusd.h:210
RADIUS_PACKET * proxy
Outgoing request to proxy server.
Definition: radiusd.h:237
main_config_t * root
Pointer to the main config hack to try and deal with hup.
Definition: radiusd.h:267
#define rad_assert(expr)
Definition: rad_assert.h:38
RFC2865 - Access-Request.
Definition: radius.h:92
#define RAD_REQUEST_OPTION_COA
Definition: radiusd.h:319
void request_data_restore(REQUEST *request, request_data_t *entry)
Add request data back to a request.
Definition: request.c:453
char const * component
Section the request is in.
Definition: radiusd.h:254
static int _request_free(REQUEST *request)
Callback for freeing a request struct.
Definition: request.c:49
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
REQUEST * coa
CoA request originated by this request.
Definition: radiusd.h:307
TALLOC_CTX * state_ctx
for request->state
Definition: radiusd.h:230
Per-request opaque data, added by modules.
Definition: request.c:33
unsigned int code
Packet code (type).
Definition: libradius.h:155
request_data_t * next
Next opaque request data struct linked to this request.
Definition: request.c:34
REQUEST * parent
Definition: radiusd.h:290
void * unique_ptr
Key to lookup request data.
Definition: request.c:36
request_data_t * data
Request metadata.
Definition: radiusd.h:216
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
#define DEBUG4(fmt,...)
Definition: log.h:178
void * opaque
Opaque data.
Definition: request.c:38
static const void * fake
Definition: rlm_sql_null.c:33
struct timeval timestamp
When we started processing the request.
Definition: radiusd.h:214
void * request_data_get(REQUEST *request, void *unique_ptr, int unique_int)
Get opaque data from a request.
Definition: request.c:374
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
void * request_data_reference(REQUEST *request, void *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
Definition: request.c:484
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
home_server_t * home_server
Definition: radiusd.h:240
#define RDEBUG4(fmt,...)
Definition: log.h:246
int unique_int
Alternative key to lookup request data.
Definition: request.c:37
bool free_on_parent
Whether to talloc_free(opaque) when the parent of the request data is freed.
Definition: request.c:40
RADCLIENT * client
The client that originally sent us the request.
Definition: radiusd.h:219
#define REQUEST_MAGIC
Definition: radiusd.h:45
#define RCSID(id)
Definition: build.h:135
char const * module
Module the request is currently being processed by.
Definition: radiusd.h:253
rad_child_state_t child_state
Definition: radiusd.h:261
uint32_t options
mainly for proxying EAP-MSCHAPv2.
Definition: radiusd.h:304
bool in_proxy_hash
Definition: radiusd.h:280
char const * server
Definition: radiusd.h:289