Delete trailing whitespace.
[freeradius.git] / src / modules / rlm_eap / mem.c
1 /*
2  * mem.c  Memory allocation, deallocation stuff.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2001,2006  The FreeRADIUS server project
21  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <stdio.h>
28 #include "rlm_eap.h"
29
30 /*
31  * Allocate a new EAP_PACKET
32  */
33 EAP_PACKET *eap_packet_alloc(void)
34 {
35         EAP_PACKET   *rp;
36
37         rp = rad_malloc(sizeof(EAP_PACKET));
38         memset(rp, 0, sizeof(EAP_PACKET));
39         return rp;
40 }
41
42 /*
43  * Free EAP_PACKET
44  */
45 void eap_packet_free(EAP_PACKET **eap_packet_ptr)
46 {
47         EAP_PACKET *eap_packet;
48
49         if (!eap_packet_ptr) return;
50         eap_packet = *eap_packet_ptr;
51         if (!eap_packet) return;
52
53         if (eap_packet->type.data) {
54                 /*
55                  * This is just a pointer in the packet
56                  * so we do not free it but we NULL it
57                 free(eap_packet->type.data);
58                 */
59                 eap_packet->type.data = NULL;
60         }
61
62         if (eap_packet->packet) {
63                 free(eap_packet->packet);
64                 eap_packet->packet = NULL;
65         }
66
67         free(eap_packet);
68
69         *eap_packet_ptr = NULL;
70 }
71
72 /*
73  * Allocate a new EAP_PACKET
74  */
75 EAP_DS *eap_ds_alloc(void)
76 {
77         EAP_DS  *eap_ds;
78
79         eap_ds = rad_malloc(sizeof(EAP_DS));
80         memset(eap_ds, 0, sizeof(EAP_DS));
81         if ((eap_ds->response = eap_packet_alloc()) == NULL) {
82                 eap_ds_free(&eap_ds);
83                 return NULL;
84         }
85         if ((eap_ds->request = eap_packet_alloc()) == NULL) {
86                 eap_ds_free(&eap_ds);
87                 return NULL;
88         }
89
90         return eap_ds;
91 }
92
93 void eap_ds_free(EAP_DS **eap_ds_p)
94 {
95         EAP_DS *eap_ds;
96
97         if (!eap_ds_p) return;
98
99         eap_ds = *eap_ds_p;
100         if (!eap_ds) return;
101
102         if (eap_ds->response) eap_packet_free(&(eap_ds->response));
103         if (eap_ds->request) eap_packet_free(&(eap_ds->request));
104
105         free(eap_ds);
106         *eap_ds_p = NULL;
107 }
108
109 /*
110  * Allocate a new EAP_HANDLER
111  */
112 EAP_HANDLER *eap_handler_alloc(void)
113 {
114         EAP_HANDLER     *handler;
115
116         handler = rad_malloc(sizeof(EAP_HANDLER));
117         memset(handler, 0, sizeof(EAP_HANDLER));
118         return handler;
119 }
120
121 void eap_handler_free(EAP_HANDLER *handler)
122 {
123         if (!handler)
124                 return;
125
126         if (handler->identity) {
127                 free(handler->identity);
128                 handler->identity = NULL;
129         }
130
131         if (handler->prev_eapds) eap_ds_free(&(handler->prev_eapds));
132         if (handler->eap_ds) eap_ds_free(&(handler->eap_ds));
133
134         if ((handler->opaque) && (handler->free_opaque)) {
135                 handler->free_opaque(handler->opaque);
136                 handler->opaque = NULL;
137         }
138         else if ((handler->opaque) && (handler->free_opaque == NULL))
139                 radlog(L_ERR, "Possible memory leak ...");
140
141         handler->opaque = NULL;
142         handler->free_opaque = NULL;
143
144         free(handler);
145 }
146
147 void eaptype_free(EAP_TYPES *i)
148 {
149         if (i->type->detach) (i->type->detach)(i->type_data);
150         i->type_data = NULL;
151         if (i->handle) lt_dlclose(i->handle);
152         free(i);
153 }
154
155
156 void eaplist_free(rlm_eap_t *inst)
157 {
158         EAP_HANDLER *node, *next;
159
160         for (node = inst->session_head; node != NULL; node = next) {
161                 next = node->next;
162                 eap_handler_free(node);
163         }
164
165         inst->session_head = inst->session_tail = NULL;
166 }
167
168 /*
169  *      Add a handler to the set of active sessions.
170  *
171  *      Since we're adding it to the list, we guess that this means
172  *      the packet needs a State attribute.  So add one.
173  */
174 int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
175 {
176         int             status;
177         VALUE_PAIR      *state;
178
179         rad_assert(handler != NULL);
180         rad_assert(handler->request != NULL);
181
182         /*
183          *      Generate State, since we've been asked to add it to
184          *      the list.
185          */
186         state = generate_state(handler->request->timestamp);
187         pairadd(&(handler->request->reply->vps), state);
188
189         /*
190          *      Create a unique 'key' for the handler, based
191          *      on State, Client-IP-Address, and EAP ID.
192          */
193         rad_assert(state->length == EAP_STATE_LEN);
194
195         /*
196          *      The time at which this request was made was the time
197          *      at which it was received by the RADIUS server.
198          */
199         handler->timestamp = handler->request->timestamp;
200         handler->status = 1;
201
202         memcpy(handler->state, state->vp_strvalue, sizeof(handler->state));
203         handler->src_ipaddr = handler->request->packet->src_ipaddr;
204         handler->eap_id = handler->eap_ds->request->id;
205
206         /*
207          *      We don't need this any more.
208          */
209         handler->request = NULL;
210
211         /*
212          *      Playing with a data structure shared among threads
213          *      means that we need a lock, to avoid conflict.
214          */
215         pthread_mutex_lock(&(inst->session_mutex));
216
217         /*
218          *      Big-time failure.
219          */
220         status = rbtree_insert(inst->session_tree, handler);
221
222         if (status) {
223                 EAP_HANDLER *prev;
224
225                 prev = inst->session_tail;
226                 if (prev) {
227                         prev->next = handler;
228                         handler->prev = prev;
229                         handler->next = NULL;
230                         inst->session_tail = handler;
231                 } else {
232                         inst->session_head = inst->session_tail = handler;
233                         handler->next = handler->prev = NULL;
234                 }
235         }
236
237         /*
238          *      Now that we've finished mucking with the list,
239          *      unlock it.
240          */
241         pthread_mutex_unlock(&(inst->session_mutex));
242
243         if (!status) {
244                 radlog(L_ERR, "rlm_eap: Failed to remember handler!");
245                 eap_handler_free(handler);
246                 return 0;
247         }
248
249         return 1;
250 }
251
252 /*
253  *      Find a a previous EAP-Request sent by us, which matches
254  *      the current EAP-Response.
255  *
256  *      Then, release the handle from the list, and return it to
257  *      the caller.
258  *
259  *      Also since we fill the eap_ds with the present EAP-Response we
260  *      got to free the prev_eapds & move the eap_ds to prev_eapds
261  */
262 EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request,
263                           eap_packet_t *eap_packet)
264 {
265         int             i;
266         VALUE_PAIR      *state;
267         rbnode_t        *node;
268         EAP_HANDLER     *handler, myHandler;
269
270         /*
271          *      We key the sessions off of the 'state' attribute, so it
272          *      must exist.
273          */
274         state = pairfind(request->packet->vps, PW_STATE);
275         if (!state ||
276             (state->length != EAP_STATE_LEN)) {
277                 return NULL;
278         }
279
280         myHandler.src_ipaddr = request->packet->src_ipaddr;
281         myHandler.eap_id = eap_packet->id;
282         memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state));
283
284         /*
285          *      Playing with a data structure shared among threads
286          *      means that we need a lock, to avoid conflict.
287          */
288         pthread_mutex_lock(&(inst->session_mutex));
289
290         /*
291          *      Check the first few handlers in the list, and delete
292          *      them if they're too old.  We don't need to check them
293          *      all, as incoming requests will quickly cause older
294          *      handlers to be deleted.
295          *
296          */
297         for (i = 0; i < 2; i++) {
298                 handler = inst->session_head;
299                 if (handler &&
300                     ((request->timestamp - handler->timestamp) > inst->timer_limit)) {
301                         node = rbtree_find(inst->session_tree, handler);
302                         rad_assert(node != NULL);
303                         rbtree_delete(inst->session_tree, node);
304
305                         inst->session_head = handler->next;
306                         if (handler->next) handler->next->prev = NULL;
307                         eap_handler_free(handler);
308                 }
309         }
310
311         handler = NULL;
312         node = rbtree_find(inst->session_tree, &myHandler);
313         if (node) {
314                 handler = rbtree_node2data(inst->session_tree, node);
315
316                 /*
317                  *      Check against replays.  The client can re-play
318                  *      a State attribute verbatim, so we wish to
319                  *      ensure that the attribute falls within the
320                  *      valid time window, which is the second at
321                  *      which it was sent out.
322                  *
323                  *      Hmm... I'm not sure that this step is
324                  *      necessary, or even that it does anything.
325                  */
326                 if (verify_state(state, handler->timestamp) != 0) {
327                         handler = NULL;
328                 } else {
329                         /*
330                          *      It's OK, delete it from the tree.
331                          */
332                         rbtree_delete(inst->session_tree, node);
333
334                         /*
335                          *      And unsplice it from the linked list.
336                          */
337                         if (handler->prev) {
338                                 handler->prev->next = handler->next;
339                         } else {
340                                 inst->session_head = handler->next;
341                         }
342                         if (handler->next) {
343                                 handler->next->prev = handler->prev;
344                         } else {
345                                 inst->session_tail = handler->prev;
346                         }
347                         handler->prev = handler->next = NULL;
348                 }
349         }
350
351         pthread_mutex_unlock(&(inst->session_mutex));
352
353         /*
354          *      Not found.
355          */
356         if (!node) {
357                 DEBUG2("  rlm_eap: Request not found in the list");
358                 return NULL;
359         }
360
361         /*
362          *      Found, but state verification failed.
363          */
364         if (!handler) {
365                 radlog(L_ERR, "rlm_eap: State verification failed.");
366                 return NULL;
367         }
368
369         DEBUG2("  rlm_eap: Request found, released from the list");
370
371         /*
372          *      Remember what the previous request was.
373          */
374         eap_ds_free(&(handler->prev_eapds));
375         handler->prev_eapds = handler->eap_ds;
376         handler->eap_ds = NULL;
377
378         return handler;
379 }