The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
mem.c
Go to the documentation of this file.
1/*
2 * mem.c Session handling, mostly taken from src/modules/rlm_eap/mem.c
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 * @copyright 2012 The FreeRADIUS server project
19 * @copyright 2012 Alan DeKok (aland@networkradius.com)
20 */
21
22#define LOG_PREFIX "securid"
23
24#include <stdio.h>
25#include "rlm_securid.h"
26
27static void securid_sessionlist_clean_expired(rlm_securid_t *inst, request_t *request, time_t timestamp);
28
30 SECURID_SESSION *session);
31
33{
34 SECURID_SESSION *session;
35
36 session = talloc_zero(NULL, SECURID_SESSION);
37 session->sdiHandle = SDI_HANDLE_NONE;
38
39 return session;
40}
41
43 SECURID_SESSION *session)
44{
45 if (!session) return;
46
47 RDEBUG2("Freeing session id=%d identity='%s' state='%s'", session->session_id,
48 SAFE_STR(session->identity), session->state);
49
50 if (session->sdiHandle != SDI_HANDLE_NONE) {
51 SD_Close(session->sdiHandle);
52 session->sdiHandle = SDI_HANDLE_NONE;
53 }
54
55 talloc_free(session);
56}
57
58
60{
61 SECURID_SESSION *node, *next;
62
63 pthread_mutex_lock(&(inst->session_mutex));
64
65 for (node = inst->session_head; node != NULL; node = next) {
66 next = node->next;
67 securid_session_free(inst,request,node);
68 }
69
70 inst->session_head = inst->session_tail = NULL;
71
72 pthread_mutex_unlock(&(inst->session_mutex));
73}
74
75
76
77/*
78 * Add a session to the set of active sessions.
79 *
80 * Since we're adding it to the list, we guess that this means
81 * the packet needs a State attribute. So add one.
82 */
84{
85 int status = 0;
86 fr_pair_t *state;
87
88 /*
89 * The time at which this request was made was the time
90 * at which it was received by the RADIUS server.
91 */
92 session->timestamp = fr_time_to_sec(request->packet->timestamp);
93
94 session->src_ipaddr = request->packet->src_ipaddr;
95
96 /*
97 * Playing with a data structure shared among threads
98 * means that we need a lock, to avoid conflict.
99 */
100 pthread_mutex_lock(&(inst->session_mutex));
101
102 /*
103 * If we have a DoS attack, discard new sessions.
104 */
105 if (fr_rb_num_elements(inst->session_tree) >= inst->max_sessions) {
107 goto done;
108 }
109
110 if (session->session_id == 0) {
111 /* this is a NEW session (we are not inserting an updated session) */
112 inst->last_session_id++;
113 session->session_id = inst->last_session_id;
114 RDEBUG2("Creating a new session with id=%d\n",session->session_id);
115 }
116
117 memset(session->state, 0, sizeof(session->state));
118 snprintf(session->state,sizeof(session->state)-1,"FRR-CH %d|%d",session->session_id,session->trips+1);
119 RDEBUG2("Inserting session id=%d identity='%s' state='%s' to the session list",
120 session->session_id,SAFE_STR(session->identity),session->state);
121
122
123 /*
124 * Generate State, since we've been asked to add it to
125 * the list.
126 */
127 MEM(pair_update_reply(&state, attr_state) >= 0);
128 fr_pair_value_memdup(state, session->state, sizeof(session->state), true);
129
130 status = fr_rb_insert(inst->session_tree, session);
131 if (status) {
132 /* tree insert SUCCESS */
133 /* insert the session to the linked list of sessions */
134 SECURID_SESSION *prev;
135
136 prev = inst->session_tail;
137 if (prev) {
138 /* insert to the tail of the list */
139 prev->next = session;
140 session->prev = prev;
141 session->next = NULL;
142 inst->session_tail = session;
143 } else {
144 /* 1st time */
145 inst->session_head = inst->session_tail = session;
146 session->next = session->prev = NULL;
147 }
148 }
149
150 /*
151 * Now that we've finished mucking with the list,
152 * unlock it.
153 */
154 done:
155 pthread_mutex_unlock(&(inst->session_mutex));
156
157 if (!status) {
158 fr_pair_list_free(&state);
159 ERROR("Failed to store session");
160 return -1;
161 }
162
163 return 0;
164}
165
166/*
167 * Find existing session if any which matches the State variable in current AccessRequest
168 * Then, release the session from the list, and return it to
169 * the caller.
170 *
171 */
173{
174 fr_pair_t *state;
175 SECURID_SESSION* session;
176 SECURID_SESSION mySession;
177
178 /* clean expired sessions if any */
179 pthread_mutex_lock(&(inst->session_mutex));
180 securid_sessionlist_clean_expired(inst, request, fr_time_to_sec(request->packet->timestamp));
181 pthread_mutex_unlock(&(inst->session_mutex));
182
183 /*
184 * We key the sessions off of the 'state' attribute
185 */
186 state = fr_pair_find_by_da(&request->request_pairs, NULL, attr_state);
187 if (!state) {
188 return NULL;
189 }
190
191 if (state->vp_length != SECURID_STATE_LEN) {
192 ERROR("Invalid State variable. length=%d", (int) state->vp_length);
193 return NULL;
194 }
195
196 memset(&mySession,0,sizeof(mySession));
197 mySession.src_ipaddr = request->packet->src_ipaddr;
198 memcpy(mySession.state, state->vp_strvalue, sizeof(mySession.state));
199
200 /*
201 * Playing with a data structure shared among threads
202 * means that we need a lock, to avoid conflict.
203 */
204 pthread_mutex_lock(&(inst->session_mutex));
205 session = securid_sessionlist_delete(inst, &mySession);
206 pthread_mutex_unlock(&(inst->session_mutex));
207
208 /*
209 * Might not have been there.
210 */
211 if (!session) {
212 ERROR("No SECURID session matching the State variable");
213 return NULL;
214 }
215
216 RDEBUG2("Session found identity='%s' state='%s', released from the list",
217 SAFE_STR(session->identity),session->state);
218 if (session->trips >= inst->max_trips_per_session) {
219 RDEBUG2("More than %d authentication packets for this SECURID session. Aborted.",inst->max_trips_per_session);
220 securid_session_free(inst,request,session);
221 return NULL;
222 }
223 session->trips++;
224
225 return session;
226}
227
228
229/************ private functions *************/
231{
232 fr_assert(fr_rb_find(inst->session_tree, session) == session);
233
234 /*
235 * Delete old session from the tree.
236 */
237 fr_rb_delete(inst->session_tree, node);
238
239 /*
240 * And unsplice it from the linked list.
241 */
242 if (session->prev) {
243 session->prev->next = session->next;
244 } else {
245 inst->session_head = session->next;
246 }
247 if (session->next) {
248 session->next->prev = session->prev;
249 } else {
250 inst->session_tail = session->prev;
251 }
252 session->prev = session->next = NULL;
253
254 return session;
255}
256
257
258static void securid_sessionlist_clean_expired(rlm_securid_t *inst, request_t *request, time_t timestamp)
259{
260 uint64_t num_sessions;
261 SECURID_SESSION *session;
262
263 num_sessions = fr_rb_num_elements(inst->session_tree);
264 RDEBUG2("There are %d sessions in the tree\n",num_sessions);
265
266 /*
267 * Delete old sessions from the list
268 *
269 */
270 while((session = inst->session_head)) {
271 if ((timestamp - session->timestamp) > inst->timer_limit) {
272 fr_rb_delete(inst->session_tree, session);
273
274 /*
275 * session == inst->session_head
276 */
277 inst->session_head = session->next;
278 if (session->next) {
279 session->next->prev = NULL;
280 } else {
281 inst->session_head = NULL;
282 inst->session_tail = NULL;
283 }
284
285 RDEBUG2("Cleaning expired session: identity='%s' state='%s'\n",
286 SAFE_STR(session->identity),session->state);
287 securid_session_free(inst,request,session);
288 } else {
289 /* no need to check all sessions since they are sorted by age */
290 break;
291 }
292 }
293}
#define UNUSED
Definition build.h:315
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
HIDDEN fr_dict_attr_t const * attr_state
Definition base.c:103
talloc_free(reap)
SECURID_SESSION * securid_sessionlist_find(rlm_securid_t *inst, request_t *request)
Definition mem.c:172
static void securid_sessionlist_clean_expired(rlm_securid_t *inst, request_t *request, time_t timestamp)
Definition mem.c:258
int securid_sessionlist_add(rlm_securid_t *inst, request_t *request, SECURID_SESSION *session)
Definition mem.c:83
SECURID_SESSION * securid_session_alloc(void)
Definition mem.c:32
static SECURID_SESSION * securid_sessionlist_delete(rlm_securid_t *inst, SECURID_SESSION *session)
Definition mem.c:230
void securid_session_free(UNUSED rlm_securid_t *inst, request_t *request, SECURID_SESSION *session)
Definition mem.c:42
void securid_sessionlist_free(rlm_securid_t *inst, request_t *request)
Definition mem.c:59
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2981
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:693
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
#define RDEBUG2(fmt,...)
Definition radclient.h:54
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
unsigned int session_id
Definition rlm_securid.h:47
fr_ipaddr_t src_ipaddr
Definition rlm_securid.h:45
SDI_HANDLE sdiHandle
Definition rlm_securid.h:40
struct _securid_session_t * next
Definition rlm_securid.h:38
struct _securid_session_t * prev
Definition rlm_securid.h:38
#define SECURID_STATE_LEN
Definition rlm_securid.h:36
char state[SECURID_STATE_LEN]
Definition rlm_securid.h:43
#define SAFE_STR(s)
Definition rlm_securid.h:8
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
eap_aka_sim_process_conf_t * inst
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
Definition time.h:731
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.