The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
track.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 (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: 108b92322170fba1c6370292af4aa988454ae00d $
19 * @file rlm_radius/track.c
20 * @brief Tracking RADUS client packets
21 *
22 * @copyright 2017 Network RADIUS SAS
23 */
24RCSID("$Id: 108b92322170fba1c6370292af4aa988454ae00d $")
25
26#include <freeradius-devel/server/base.h>
27#include <freeradius-devel/io/application.h>
28
29#include "track.h"
30
31/** Create an radius_track_t
32 *
33 * @param ctx the talloc ctx
34 * @return
35 * - NULL on error
36 * - radius_track_t on success
37 */
39{
40 int i;
42
43 MEM(tt = talloc_zero(ctx, radius_track_t));
44
46
47 for (i = 0; i < 256; i++) {
48 tt->id[i].id = i;
49#ifndef NDEBUG
50 tt->id[i].file = __FILE__;
51 tt->id[i].line = __LINE__;
52#endif
53 fr_dlist_insert_tail(&tt->free_list, &tt->id[i]);
54 }
55
56 return tt;
57}
58
59
60/** Ensures the entry is released when the ctx passed to radius_track_entry_reserve is freed
61 *
62 * @param[in] te_p Entry to release.
63 * @return 0
64 */
66{
67 /*
68 * This function is a talloc destructor for the binding. We therefore zero out the te->binding
69 * in the entry before calling radius_track_entry_release(). Otherwise it will try to
70 * talloc_free() the binding, even though we're already in the process of freeing it.
71 */
72 (**te_p)->binding = NULL;
73
75
76 return 0;
77}
78
79/** Allocate a tracking entry.
80 *
81 * @param[in] file The allocation was made in.
82 * @param[in] line The allocation was made on.
83 * @param[out] te_out Where the tracking entry should be written.
84 * If ctx is not-null, then this pointer must
85 * remain valid for the lifetime of the ctx.
86 * @param[in] ctx If not-null, the tracking entry release will
87 * be bound to the lifetime of the talloc chunk.
88 * @param[in] tt The radius_track_t tracking table.
89 * @param[in] request The request which will send the proxied packet.
90 * @param[in] code Of the outbound request.
91 * @param[in] uctx The context to associate with the request
92 * @return
93 * - 0 on success.
94 * - -1 on failure.
95 */
96#ifndef NDEBUG
98#else
100#endif
101 radius_track_entry_t **te_out,
102 TALLOC_CTX *ctx, radius_track_t *tt, request_t *request, uint8_t code, void *uctx)
103{
105
106 if (!fr_cond_assert_msg(!*te_out, "Expected tracking entry to be NULL")) return -1;
107
108retry:
109 te = fr_dlist_head(&tt->free_list);
110 if (te) {
111 fr_assert(te->request == NULL);
112
113 /*
114 * Mark it as used, and remove it from the free list.
115 */
116 fr_dlist_remove(&tt->free_list, te);
117
118 /*
119 * We've transitioned from "use it", to "oops,
120 * don't use it". Ensure that we only return IDs
121 * which are in the static array.
122 */
123 if (te != &tt->id[te->id]) {
124 talloc_free(te);
125 goto retry;
126 }
127
128 goto done;
129 }
130
131 /*
132 * There are no free entries, and we can't use the
133 * Request Authenticator. Oh well...
134 */
135 fr_strerror_const("No free entries");
136 return -1;
137
138done:
139 te->tt = tt;
140 te->request = request;
141 te->uctx = uctx;
142 te->code = code;
143#ifndef NDEBUG
144 te->operation = te->tt->operation++;
145 te->file = file;
146 te->line = line;
147#endif
148 if (ctx) {
149 MEM(te->binding = talloc_zero(ctx, radius_track_entry_t **));
150 talloc_set_destructor(te->binding, _radius_track_entry_release_on_free);
151 *(te->binding) = te_out;
152 }
153
154 /*
155 * te->id is already allocated
156 */
157 tt->num_requests++;
158
159 *te_out = te;
160
161 return 0;
162}
163
164/** Release a tracking entry
165 *
166 * @param[in] file Allocation was released in.
167 * @param[in] line Allocation was released on.
168 * @param[in,out] te_to_free The #radius_track_entry_t allocated via #radius_track_entry_reserve.
169 * @return
170 * - <0 on error
171 * - 0 on success
172 */
173#ifndef NDEBUG
175#else
177#endif
178 radius_track_entry_t **te_to_free)
179{
180 radius_track_entry_t *te = *te_to_free;
181 radius_track_t *tt;
182
183 if (!te) return 0;
184
185 tt = talloc_get_type_abort(te->tt, radius_track_t); /* Make sure table is still valid */
186
187 if (te->binding) {
188 talloc_set_destructor(te->binding, NULL); /* Disarm the destructor */
189 talloc_free(te->binding);
190 }
191
192#ifndef NDEBUG
193 te->operation = te->tt->operation++;
194 te->file = file;
195 te->line = line;
196#endif
197
198 te->request = NULL;
199
200 fr_assert(tt->num_requests > 0);
201 tt->num_requests--;
202
203 /*
204 * We're freeing a static ID, just go do that...
205 */
206 fr_assert(te == &tt->id[te->id]);
207
209
210 *te_to_free = NULL;
211
212 return 0;
213}
214
215/** Update a tracking entry with the authentication vector
216 *
217 * @param te The radius_track_entry_t, via radius_track_entry_reserve()
218 * @param vector The authentication vector for the packet we're sending
219 * @return
220 * - <0 on error
221 * - 0 on success
222 */
224{
225#ifndef NDEBUG
226 radius_track_t *tt = te->tt;
227#endif
228
229 fr_assert(tt);
230
231 memcpy(te->vector, vector, sizeof(te->vector));
232
233 /*
234 * If we're not using the Request Authenticator, the
235 * tracking entry must be in the static array.
236 *
237 * @todo - gracefully handle fallback if the server screws up.
238 */
239 fr_assert(te == &tt->id[te->id]);
240 return 0;
241}
242
243/** Find a tracking entry from a request authenticator
244 *
245 * @param tt The radius_track_t tracking table
246 * @param packet_id The ID from the RADIUS header
247 * @param vector The Request Authenticator (may be NULL)
248 * @return
249 * - NULL on "not found"
250 * - radius_track_entry_t on success
251 */
253{
255
256 (void) talloc_get_type_abort(tt, radius_track_t);
257
258 /*
259 * Just use the static array.
260 */
261 te = &tt->id[packet_id];
262
263 /*
264 * Not in use, die.
265 */
266 if (!te->request) return NULL;
267
268 if (!vector) return te;
269
270 /*
271 * Protocol-Error and Original-Packet-Vector <sigh>
272 *
273 * This should arguably have been Original-Packet-Code, but we are stupid.
274 *
275 * @todo - Allow for multiple ID arrays, one for each packet code. Or, just switch to using
276 * src/protocols/radius/id.[ch].
277 */
278 if (memcmp(te->vector, vector, sizeof(te->vector)) != 0) return NULL;
279
280 /*
281 * Ignore the Request Authenticator, as the
282 * caller doesn't have it.
283 */
284 return te;
285}
286
287
288#ifndef NDEBUG
289/** Print out the state of every tracking entry
290 *
291 * @param[in] log destination.
292 * @param[in] log_type Type of log message.
293 * @param[in] file this function was called in.
294 * @param[in] line this function was called on.
295 * @param[in] tt Table to print.
296 * @param[in] extra Callback function for printing extra detail.
297 */
298void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
300{
301 size_t i;
302
303 for (i = 0; i < NUM_ELEMENTS(tt->id); i++) {
305
306 entry = &tt->id[i];
307
308 if (entry->request) {
309 fr_log(log, log_type, file, line,
310 "[%zu] %"PRIu64 " - Allocated at %s:%u to request %p (%s), uctx %p",
311 i, entry->operation,
312 entry->file, entry->line, entry->request, entry->request->name, entry->uctx);
313 } else {
314 fr_log(log, log_type, file, line,
315 "[%zu] %"PRIu64 " - Freed at %s:%u",
316 i, entry->operation, entry->file, entry->line);
317 }
318
319 if (extra) extra(log, log_type, file, line, entry);
320 }
321}
322#endif
int const char * file
Definition acutest.h:702
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:506
#define NUM_ELEMENTS(_t)
Definition build.h:358
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:158
#define MEM(x)
Definition debug.h:46
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:242
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:468
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:360
talloc_free(hp)
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:577
fr_log_type_t
Definition log.h:51
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
Definition log.h:93
void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_t *tt, radius_track_log_extra_t extra)
Print out the state of every tracking entry.
Definition track.c:298
int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
Update a tracking entry with the authentication vector.
Definition track.c:223
radius_track_entry_t * radius_track_entry_find(radius_track_t *tt, uint8_t packet_id, uint8_t const *vector)
Find a tracking entry from a request authenticator.
Definition track.c:252
int _radius_track_entry_reserve(char const *file, int line, radius_track_entry_t **te_out, TALLOC_CTX *ctx, radius_track_t *tt, request_t *request, uint8_t code, void *uctx)
Allocate a tracking entry.
Definition track.c:97
int _radius_track_entry_release(char const *file, int line, radius_track_entry_t **te_to_free)
Release a tracking entry.
Definition track.c:174
static int _radius_track_entry_release_on_free(radius_track_entry_t ***te_p)
Ensures the entry is released when the ctx passed to radius_track_entry_reserve is freed.
Definition track.c:65
radius_track_t * radius_track_alloc(TALLOC_CTX *ctx)
Create an radius_track_t.
Definition track.c:38
char const * file
Where the entry was allocated.
Definition track.h:59
fr_dlist_head_t free_list
so we allocate by least recently used
Definition track.h:67
radius_track_t * tt
Definition track.h:39
#define radius_track_entry_release(_te)
Definition track.h:90
void * uctx
Result/resumption context.
Definition track.h:47
int line
Where the entry was freed.
Definition track.h:60
uint8_t id
our ID
Definition track.h:50
uint64_t operation
Incremented each alloc and de-alloc.
Definition track.h:72
unsigned int num_requests
number of requests in the allocation
Definition track.h:65
uint8_t code
packet code (sigh)
Definition track.h:49
radius_track_entry_t id[UINT8_MAX+1]
which ID was used
Definition track.h:69
#define radius_track_entry_reserve(_te_out, _ctx, _tt, _request, _code, _uctx)
Definition track.h:82
void(* radius_track_log_extra_t)(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_entry_t *te)
Definition track.h:95
uint64_t operation
Used to give an idea of the alloc/free timeline.
Definition track.h:58
request_t * request
as always...
Definition track.h:45
radius_track_entry_t *** binding
Binding chunk we use to release the entry when its parent is freed.
Definition track.h:41
Track one request to a response.
Definition track.h:36
#define fr_strerror_const(_msg)
Definition strerror.h:223