All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
state.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: 2a000258fd4f4d9b1b374adc3229da85eb355c18 $
19  *
20  * @brief Multi-packet state handling
21  * @file main/state.c
22  *
23  * @ingroup AVP
24  *
25  * For each round of a multi-round authentication method such as EAP,
26  * or a 2FA method such as OTP, a state entry will be created. The state
27  * entry holds data that should be available during the complete lifecycle
28  * of the authentication attempt.
29  *
30  * When a request is complete, #fr_request_to_state is called to transfer
31  * ownership of the state VALUE_PAIRs and state_ctx (which the VALUE_PAIRs
32  * are allocated in) to a #fr_state_entry_t. This #fr_state_entry_t holds the
33  * value of the State attribute, that will be send out in the response.
34  *
35  * When the next request is received, #fr_state_to_request is called to transfer
36  * the VALUE_PAIRs and state ctx to the new request.
37  *
38  * The ownership of the state_ctx and state VALUE_PAIRs is transferred as below:
39  *
40  * @verbatim
41  request -> state_entry -> request -> state_entry -> request -> free()
42  \-> reply \-> reply \-> access-reject/access-accept
43  * @endverbatim
44  *
45  * @copyright 2014 The FreeRADIUS server project
46  */
47 RCSID("$Id: 2a000258fd4f4d9b1b374adc3229da85eb355c18 $")
48 
49 #include <freeradius-devel/radiusd.h>
50 #include <freeradius-devel/state.h>
51 #include <freeradius-devel/rad_assert.h>
52 
53 /** Holds a state value, and associated VALUE_PAIRs and data
54  *
55  */
56 typedef struct state_entry {
57  uint64_t id; //!< State ID for debugging
58  uint8_t state[AUTH_VECTOR_LEN]; //!< State value in binary.
59 
60  time_t cleanup; //!< When this entry should be cleaned up.
61  struct state_entry *prev; //!< Previous entry in the cleanup list.
62  struct state_entry *next; //!< Next entry in the cleanup list.
63 
64  int tries;
65 
66  TALLOC_CTX *ctx; //!< ctx to parent any data that needs to be
67  //!< tied to the lifetime of the request progression.
68  VALUE_PAIR *vps; //!< session-state VALUE_PAIRs, parented by ctx.
69 
70  request_data_t *data; //!< Persistable request data, also parented ctx.
72 
74  uint64_t id; //!< Next ID to assign.
75  uint64_t timed_out; //!< Number of states that were cleaned up due to
76  //!< timeout.
77  uint32_t max_sessions; //!< Maximum number of sessions we track.
78  rbtree_t *tree; //!< rbtree used to lookup state value.
79 
80  fr_state_entry_t *head, *tail; //!< Entries to expire.
81  uint32_t timeout; //!< How long to wait before cleaning up state entires.
82 #ifdef HAVE_PTHREAD_H
83  pthread_mutex_t mutex; //!< Synchronisation mutex.
84 #endif
85 };
86 
88 
89 #ifdef HAVE_PTHREAD_H
90 # define PTHREAD_MUTEX_LOCK if (main_config.spawn_workers) pthread_mutex_lock
91 # define PTHREAD_MUTEX_UNLOCK if (main_config.spawn_workers) pthread_mutex_unlock
92 #else
93 /*
94  * This is easier than ifdef's throughout the code.
95  */
96 # define PTHREAD_MUTEX_LOCK(_x)
97 # define PTHREAD_MUTEX_UNLOCK(_x)
98 #endif
99 
101 
102 /** Compare two fr_state_entry_t based on their state value i.e. the value of the attribute
103  *
104  */
105 static int state_entry_cmp(void const *one, void const *two)
106 {
107  fr_state_entry_t const *a = one;
108  fr_state_entry_t const *b = two;
109 
110  return memcmp(a->state, b->state, sizeof(a->state));
111 }
112 
113 /** Free the state tree
114  *
115  */
117 {
118  fr_state_entry_t *this;
119 
120 #ifdef HAVE_PTHREAD_H
121  if (main_config.spawn_workers) pthread_mutex_destroy(&state->mutex);
122 #endif
123 
124  DEBUG4("Freeing state tree %p", state);
125 
126  while (state->head) {
127  this = state->head;
128  state_entry_unlink(state, this);
129  talloc_free(this);
130  }
131 
132  for (this = state->head; this; this = this->next) DEBUG4("State %" PRIu64 " needs freeing prev was %" PRIu64 "", this->id, this->prev ? this->prev->id : 100000);
133 
134  /*
135  * Ensure we got *all* the entries
136  */
137  rad_assert(!state->head);
138 
139  /*
140  * Free the rbtree
141  */
142  rbtree_free(state->tree);
143 
144  if (state == global_state) global_state = NULL;
145 
146  return 0;
147 }
148 
149 /** Initialise a new state tree
150  *
151  * @param ctx to link the lifecycle of the state tree to.
152  * @param max_sessions we track state for.
153  * @param timeout How long to wait before cleaning up entries.
154  * @return a new state tree or NULL on failure.
155  */
156 fr_state_tree_t *fr_state_tree_init(TALLOC_CTX *ctx, uint32_t max_sessions, uint32_t timeout)
157 {
159 
160  state = talloc_zero(NULL, fr_state_tree_t);
161  if (!state) return 0;
162 
163  state->max_sessions = max_sessions;
164  state->timeout = timeout;
165 
166  /*
167  * Create a break in the contexts.
168  * We still want this to be freed at the same time
169  * as the parent, but we also need it to be thread
170  * safe, and multiple threads could be using the
171  * tree.
172  */
173  fr_talloc_link_ctx(ctx, state);
174 
175 #ifdef HAVE_PTHREAD_H
176  if (main_config.spawn_workers && (pthread_mutex_init(&state->mutex, NULL) != 0)) {
177  talloc_free(state);
178  return NULL;
179  }
180 #endif
181 
182  /*
183  * We need to do controlled freeing of the
184  * rbtree, so that all the state entries
185  * are freed before it's destroyed. Hence
186  * it being parented from the NULL ctx.
187  */
188  state->tree = rbtree_create(NULL, state_entry_cmp, NULL, 0);
189  if (!state->tree) {
190  talloc_free(state);
191  return NULL;
192  }
193  talloc_set_destructor(state, _state_tree_free);
194 
195  return state;
196 }
197 
198 /** Unlink an entry and remove if from the tree
199  *
200  */
202 {
203  fr_state_entry_t *prev, *next;
204 
205  prev = entry->prev;
206  next = entry->next;
207 
208  if (prev) {
209  rad_assert(state->head != entry);
210  prev->next = next;
211  } else if (state->head) {
212  rad_assert(state->head == entry);
213  state->head = next;
214  }
215 
216  if (next) {
217  rad_assert(state->tail != entry);
218  next->prev = prev;
219  } else if (state->tail) {
220  rad_assert(state->tail == entry);
221  state->tail = prev;
222  }
223  entry->next = NULL;
224  entry->prev = NULL;
225 
226  rbtree_deletebydata(state->tree, entry);
227 
228  DEBUG4("State ID %" PRIu64 " unlinked", entry->id);
229 }
230 
231 /** Frees any data associated with a state
232  *
233  */
235 {
236 #ifdef WITH_VERIFY_PTR
237  vp_cursor_t cursor;
238  VALUE_PAIR *vp;
239 
240  /*
241  * Verify all state attributes are parented
242  * by the state context.
243  */
244  if (entry->ctx) {
245  for (vp = fr_cursor_init(&cursor, &entry->vps);
246  vp;
247  vp = fr_cursor_next(&cursor)) {
248  rad_assert(entry->ctx == talloc_parent(vp));
249  }
250  }
251 
252  /*
253  * Ensure any request data is parented by us
254  * so we know it'll be cleaned up.
255  */
256  if (entry->data) rad_assert(request_data_verify_parent(entry->ctx, entry->data));
257 #endif
258 
259  /*
260  * Should also free any state attributes
261  */
262  if (entry->ctx) TALLOC_FREE(entry->ctx);
263 
264  DEBUG4("State ID %" PRIu64 " freed", entry->id);
265 
266  return 0;
267 }
268 
269 /** Create a new state entry
270  *
271  * @note Called with the mutex held.
272  */
274 {
275  size_t i;
276  uint32_t x;
277  time_t now = time(NULL);
278  VALUE_PAIR *vp;
279  fr_state_entry_t *entry, *next;
280  fr_state_entry_t *free_head = NULL, **free_next = &free_head;
281 
282  uint8_t old_state[AUTH_VECTOR_LEN];
283  int old_tries = 0;
284 
285  /*
286  * Clean up old entries.
287  */
288  for (entry = state->head; entry != NULL; entry = next) {
289  next = entry->next;
290 
291  if (entry == old) continue;
292 
293  /*
294  * Too old, we can delete it.
295  */
296  if (entry->cleanup < now) {
297  state_entry_unlink(state, entry);
298  *free_next = entry;
299  free_next = &(entry->next);
300  state->timed_out++;
301  continue;
302  }
303 
304  break;
305  }
306 
307  if (rbtree_num_elements(state->tree) >= (uint32_t) state->max_sessions) return NULL;
308 
309  /*
310  * Record the information from the old state, we may base the
311  * new state off the old one.
312  *
313  * Once we release the mutex, the state of old becomes indeterminate
314  * so we have to grab the values now.
315  */
316  if (old) {
317  old_tries = old->tries;
318 
319  memcpy(old_state, old->state, sizeof(old_state));
320 
321  /*
322  * The old one isn't used any more, so we can free it.
323  */
324  if (!old->data) {
325  state_entry_unlink(state, old);
326  *free_next = old;
327  }
328  }
329  PTHREAD_MUTEX_UNLOCK(&state->mutex);
330 
331  /*
332  * Now free the unlinked entries.
333  *
334  * We do it here as freeing may involve significantly more
335  * work than just freeing the data.
336  *
337  * If there's request data that was persisted it will now
338  * be freed also, and it may have complex destructors associated
339  * with it.
340  */
341  for (next = free_head; next;) {
342  entry = next;
343  next = entry->next;
344  talloc_free(entry);
345  }
346 
347  /*
348  * Allocation doesn't need to occur inside the critical region
349  * and would add significantly to contention.
350  *
351  * We reparent the talloc chunk later (when we hold the mutex again)
352  * we can't do it now due to thread safety issues with talloc.
353  */
354  entry = talloc_zero(NULL, fr_state_entry_t);
355  if (!entry) {
356  PTHREAD_MUTEX_LOCK(&state->mutex); /* Caller expects this to be locked */
357  return NULL;
358  }
359  talloc_set_destructor(entry, _state_entry_free);
360  entry->id = state->id++;
361 
362  /*
363  * Limit the lifetime of this entry based on how long the
364  * server takes to process a request. Doing it this way
365  * isn't perfect, but it's reasonable, and it's one less
366  * thing for an administrator to configure.
367  */
368  entry->cleanup = now + state->timeout;
369 
370  /*
371  * Some modules like rlm_otp create their own magic
372  * state attributes. If a state value already exists
373  * int the reply, we use that in preference to the
374  * old state.
375  */
376  vp = fr_pair_find_by_num(packet->vps, 0, PW_STATE, TAG_ANY);
377  if (vp) {
378  if (DEBUG_ENABLED && (vp->vp_length > sizeof(entry->state))) {
379  WARN("State too long, will be truncated. Expected <= %zd bytes, got %zu bytes",
380  sizeof(entry->state), vp->vp_length);
381  }
382  memcpy(entry->state, vp->vp_octets, sizeof(entry->state));
383  } else {
384  /*
385  * Base the new state on the old state if we had one.
386  */
387  if (old) {
388  memcpy(entry->state, old_state, sizeof(entry->state));
389  entry->tries = old_tries + 1;
390  }
391 
392  entry->state[0] = entry->tries + 1;
393  entry->state[1] = entry->state[0] ^ entry->tries;
394  entry->state[8] = entry->state[2] ^ ((((uint32_t) HEXIFY(RADIUSD_VERSION)) >> 16) & 0xff);
395  entry->state[10] = entry->state[2] ^ ((((uint32_t) HEXIFY(RADIUSD_VERSION)) >> 8) & 0xff);
396  entry->state[12] = entry->state[2] ^ (((uint32_t) HEXIFY(RADIUSD_VERSION)) & 0xff);
397 
398  /*
399  * 16 octets of randomness should be enough to
400  * have a globally unique state.
401  */
402  for (i = 0; i < sizeof(entry->state) / sizeof(x); i++) {
403  x = fr_rand();
404  memcpy(entry->state + (i * 4), &x, sizeof(x));
405  }
406 
407  /*
408  * Allow a portion ofthe State attribute to be set.
409  *
410  * This allows load-balancing proxies to be much
411  * less stateful.
412  */
413  if (main_config.state_seed < 256) entry->state[3] = main_config.state_seed;
414 
415  vp = fr_pair_afrom_num(packet, 0, PW_STATE);
416  fr_pair_value_memcpy(vp, entry->state, sizeof(entry->state));
417  fr_pair_add(&packet->vps, vp);
418  }
419 
420  if (DEBUG_ENABLED4) {
421  char hex[(sizeof(entry->state) * 2) + 1];
422 
423  fr_bin2hex(hex, entry->state, sizeof(entry->state));
424 
425  DEBUG4("State ID %" PRIu64 " created, value 0x%s, expires %" PRIu64 "s",
426  entry->id, hex, (uint64_t)entry->cleanup - now);
427  }
428 
429  PTHREAD_MUTEX_LOCK(&state->mutex);
430  if (rbtree_num_elements(state->tree) >= (uint32_t) state->max_sessions) {
431  talloc_free(entry);
432  return NULL;
433  }
434 
435  if (!rbtree_insert(state->tree, entry)) {
436  talloc_free(entry);
437  return NULL;
438  }
439 
440  /*
441  * Link it to the end of the list, which is implicitely
442  * ordered by cleanup time.
443  */
444  if (!state->head) {
445  entry->prev = entry->next = NULL;
446  state->head = state->tail = entry;
447  } else {
448  rad_assert(state->tail != NULL);
449 
450  entry->prev = state->tail;
451  state->tail->next = entry;
452 
453  entry->next = NULL;
454  state->tail = entry;
455  }
456 
457  return entry;
458 }
459 
460 /** Find the entry, based on the State attribute
461  *
462  */
464 {
465  VALUE_PAIR *vp;
466  fr_state_entry_t *entry, my_entry;
467 
468  vp = fr_pair_find_by_num(packet->vps, 0, PW_STATE, TAG_ANY);
469  if (!vp) return NULL;
470 
471  if (vp->vp_length != sizeof(my_entry.state)) return NULL;
472 
473  memcpy(my_entry.state, vp->vp_octets, sizeof(my_entry.state));
474 
475  entry = rbtree_finddata(state->tree, &my_entry);
476 
477 #ifdef WITH_VERIFY_PTR
478  if (entry) (void) talloc_get_type_abort(entry, fr_state_entry_t);
479 #endif
480 
481  return entry;
482 }
483 
484 /** Called when sending an Access-Accept/Access-Reject to discard state information
485  *
486  */
488 {
489  fr_state_entry_t *entry;
490 
491  PTHREAD_MUTEX_LOCK(&state->mutex);
492  entry = state_entry_find(state, original);
493  if (!entry) {
494  PTHREAD_MUTEX_UNLOCK(&state->mutex);
495  return;
496  }
497  state_entry_unlink(state, entry);
498  PTHREAD_MUTEX_UNLOCK(&state->mutex);
499 
500  /*
501  * The state and request must be in the same state
502  * as if we'd called fr_request_to_state, before
503  * we free the state entry, otherwise we leak memory.
504  */
505  entry->ctx = request->state_ctx;
506  entry->vps = request->state;
507  request_data_by_persistance(&entry->data, request, true);
508 
509  request->state_ctx = NULL;
510  request->state = NULL;
511  TALLOC_FREE(entry);
512 
513  return;
514 }
515 
516 /** Copy a pointer to the head of the list of state VALUE_PAIRs (and their ctx) into the request
517  *
518  * @note Does not copy the actual VALUE_PAIRs. The VALUE_PAIRs and their context
519  * are transferred between state entries as the conversation progresses.
520  *
521  * @note Called with the mutex free.
522  */
524 {
525  fr_state_entry_t *entry;
526  TALLOC_CTX *old_ctx = NULL;
527 
528  rad_assert(request->state == NULL);
529 
530  /*
531  * No State, don't do anything.
532  */
533  if (!fr_pair_find_by_num(request->packet->vps, 0, PW_STATE, TAG_ANY)) {
534  RDEBUG3("No &request:State attribute, can't restore &session-state");
535  return;
536  }
537 
538  PTHREAD_MUTEX_LOCK(&state->mutex);
539 
540  entry = state_entry_find(state, packet);
541  if (entry) {
542  if (request->state_ctx) old_ctx = request->state_ctx;
543 
544  request->state_ctx = entry->ctx;
545  request->state = entry->vps;
546  request_data_restore(request, entry->data);
547 
548  entry->ctx = NULL;
549  entry->vps = NULL;
550  entry->data = NULL;
551  }
552 
553  PTHREAD_MUTEX_UNLOCK(&state->mutex);
554 
555  if (request->state) {
556  RDEBUG2("Restored &session-state");
557  rdebug_pair_list(L_DBG_LVL_2, request, request->state, "&session-state:");
558  } else {
559  RDEBUG3("No &session-state attributes to restore");
560  }
561 
562  /*
563  * Free this outside of the mutex for less contention.
564  */
565  if (old_ctx) talloc_free(old_ctx);
566 
567  VERIFY_REQUEST(request);
568  return;
569 }
570 
571 
572 /** Transfer ownership of the state VALUE_PAIRs and ctx, back to a state entry
573  *
574  * Put request->state into the State attribute. Put the State attribute
575  * into the vps list. Delete the original entry, if it exists
576  *
577  * Also creates a new state entry.
578  */
580 {
581  fr_state_entry_t *entry, *old;
583 
584  request_data_by_persistance(&data, request, true);
585 
586  if (request->state && !data) return true;
587 
588  if (request->state) {
589  RDEBUG2("Saving &session-state");
590  rdebug_pair_list(L_DBG_LVL_2, request, request->state, "&session-state:");
591  }
592 
593  PTHREAD_MUTEX_LOCK(&state->mutex);
594 
595  old = original ? state_entry_find(state, original) :
596  NULL;
597 
598  entry = state_entry_create(state, packet, old);
599  if (!entry) {
600  PTHREAD_MUTEX_UNLOCK(&state->mutex);
601  return false;
602  }
603 
604  rad_assert(entry->ctx == NULL);
605  rad_assert(request->state_ctx);
606 
607  entry->ctx = request->state_ctx;
608  entry->vps = request->state;
609  entry->data = data;
610 
611  request->state_ctx = NULL;
612  request->state = NULL;
613 
614  PTHREAD_MUTEX_UNLOCK(&state->mutex);
615 
616  rad_assert(request->state == NULL);
617  VERIFY_REQUEST(request);
618  return true;
619 }
620 
621 /** Return number of entries created
622  *
623  */
625 {
626  return state->id;
627 }
628 
629 /** Return number of entries that timed out
630  *
631  */
633 {
634  return state->timed_out;
635 }
636 
637 /** Return number of entries we're currently tracking
638  *
639  */
641 {
642  return (uint32_t)rbtree_num_elements(state->tree);
643 }
2nd highest priority debug messages (-xx | -X).
Definition: log.h:52
#define pthread_mutex_init(_x, _y)
Definition: rlm_eap.h:75
void rbtree_free(rbtree_t *tree)
Definition: rbtree.c:84
Main server configuration.
Definition: radiusd.h:108
bool rbtree_deletebydata(rbtree_t *tree, void const *data)
Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
Definition: rbtree.c:496
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
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
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
static int state_entry_cmp(void const *one, void const *two)
Compare two fr_state_entry_t based on their state value i.e.
Definition: state.c:105
rbtree_t * tree
rbtree used to lookup state value.
Definition: state.c:78
static fr_state_entry_t * state_entry_create(fr_state_tree_t *state, RADIUS_PACKET *packet, fr_state_entry_t *old)
Create a new state entry.
Definition: state.c:273
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
uint32_t fr_state_entries_tracked(fr_state_tree_t *state)
Return number of entries we're currently tracking.
Definition: state.c:640
static float timeout
Definition: radclient.c:43
void * rbtree_finddata(rbtree_t *tree, void const *data)
Find the user data.
Definition: rbtree.c:537
#define VERIFY_REQUEST(_x)
Definition: radiusd.h:188
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
VALUE_PAIR * vps
session-state VALUE_PAIRs, parented by ctx.
Definition: state.c:68
#define rad_assert(expr)
Definition: rad_assert.h:38
struct state_entry * prev
Previous entry in the cleanup list.
Definition: state.c:61
fr_state_entry_t * tail
Entries to expire.
Definition: state.c:80
uint64_t id
State ID for debugging.
Definition: state.c:57
rbtree_t * rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
Create a new RED-BLACK tree.
Definition: rbtree.c:112
#define AUTH_VECTOR_LEN
Definition: libradius.h:118
uint64_t fr_state_entries_created(fr_state_tree_t *state)
Return number of entries created.
Definition: state.c:624
#define PTHREAD_MUTEX_UNLOCK(_x)
Definition: state.c:97
void fr_state_to_request(fr_state_tree_t *state, REQUEST *request, RADIUS_PACKET *packet)
Copy a pointer to the head of the list of state VALUE_PAIRs (and their ctx) into the request...
Definition: state.c:523
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
struct state_entry fr_state_entry_t
Holds a state value, and associated VALUE_PAIRs and data.
static int _state_tree_free(fr_state_tree_t *state)
Free the state tree.
Definition: state.c:116
TALLOC_CTX * state_ctx
for request->state
Definition: radiusd.h:230
Per-request opaque data, added by modules.
Definition: request.c:33
#define DEBUG_ENABLED4
True if global debug level 1-4 messages are enabled.
Definition: log.h:172
uint32_t max_sessions
Maximum number of sessions we track.
Definition: state.c:77
struct state_entry * next
Next entry in the cleanup list.
Definition: state.c:62
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
uint8_t state[AUTH_VECTOR_LEN]
State value in binary.
Definition: state.c:58
request_data_t * data
Persistable request data, also parented ctx.
Definition: state.c:70
uint32_t state_seed
magic for proxying
Definition: radiusd.h:165
#define DEBUG4(fmt,...)
Definition: log.h:178
void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of VALUE_PAIRs.
Definition: pair.c:757
#define RDEBUG2(fmt,...)
Definition: log.h:244
TALLOC_CTX * ctx
ctx to parent any data that needs to be tied to the lifetime of the request progression.
Definition: state.c:66
unsigned int state
Definition: proto_bfd.c:200
uint8_t data[]
Definition: eap_pwd.h:625
#define TAG_ANY
Definition: pair.h:191
void request_data_restore(REQUEST *request, request_data_t *entry)
Add request data back to a request.
Definition: request.c:453
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
#define HEXIFY(b1)
Definition: build.h:51
VALUE_PAIR * state
VALUE_PAIR (s) available over the lifetime of the authentication attempt.
Definition: radiusd.h:231
static int _state_entry_free(fr_state_entry_t *entry)
Frees any data associated with a state.
Definition: state.c:234
bool rbtree_insert(rbtree_t *tree, void *data)
Definition: rbtree.c:329
fr_state_entry_t * head
Definition: state.c:80
uint32_t timeout
How long to wait before cleaning up state entires.
Definition: state.c:81
fr_state_tree_t * fr_state_tree_init(TALLOC_CTX *ctx, uint32_t max_sessions, uint32_t timeout)
Initialise a new state tree.
Definition: state.c:156
bool fr_request_to_state(fr_state_tree_t *state, REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *packet)
Transfer ownership of the state VALUE_PAIRs and ctx, back to a state entry.
Definition: state.c:579
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
#define WARN(fmt,...)
Definition: log.h:144
int fr_talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
Link a parent and a child context, so the child is freed before the parent.
Definition: misc.c:105
time_t cleanup
When this entry should be cleaned up.
Definition: state.c:60
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
int tries
Definition: state.c:64
uint64_t timed_out
Number of states that were cleaned up due to timeout.
Definition: state.c:75
static void state_entry_unlink(fr_state_tree_t *state, fr_state_entry_t *entry)
Unlink an entry and remove if from the tree.
Definition: state.c:201
static char const hex[]
Definition: smbencrypt.c:34
#define PTHREAD_MUTEX_LOCK(_x)
Definition: state.c:96
bool spawn_workers
Should the server spawn threads.
Definition: radiusd.h:122
void fr_state_discard(fr_state_tree_t *state, REQUEST *request, RADIUS_PACKET *original)
Called when sending an Access-Accept/Access-Reject to discard state information.
Definition: state.c:487
Holds a state value, and associated VALUE_PAIRs and data.
Definition: state.c:56
#define pthread_mutex_destroy(_x)
Definition: rlm_eap.h:76
#define RCSID(id)
Definition: build.h:135
static fr_state_entry_t * state_entry_find(fr_state_tree_t *state, RADIUS_PACKET *packet)
Find the entry, based on the State attribute.
Definition: state.c:463
#define DEBUG_ENABLED
True if global debug level 1 messages are enabled.
Definition: log.h:169
uint64_t id
Next ID to assign.
Definition: state.c:74
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
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
uint64_t fr_state_entries_timeout(fr_state_tree_t *state)
Return number of entries that timed out.
Definition: state.c:632
uint32_t rbtree_num_elements(rbtree_t *tree)
Definition: rbtree.c:727
#define RDEBUG3(fmt,...)
Definition: log.h:245
fr_state_tree_t * global_state
Definition: state.c:87