2 * mem.c Memory allocation, deallocation stuff.
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.
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.
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
20 * Copyright 2000,2001,2006 The FreeRADIUS server project
21 * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
24 #include <freeradius-devel/ident.h>
31 * Allocate a new EAP_PACKET
33 EAP_PACKET *eap_packet_alloc(void)
37 rp = rad_malloc(sizeof(EAP_PACKET));
38 memset(rp, 0, sizeof(EAP_PACKET));
45 void eap_packet_free(EAP_PACKET **eap_packet_ptr)
47 EAP_PACKET *eap_packet;
49 if (!eap_packet_ptr) return;
50 eap_packet = *eap_packet_ptr;
51 if (!eap_packet) return;
53 if (eap_packet->type.data) {
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);
59 eap_packet->type.data = NULL;
62 if (eap_packet->packet) {
63 free(eap_packet->packet);
64 eap_packet->packet = NULL;
69 *eap_packet_ptr = NULL;
73 * Allocate a new EAP_PACKET
75 EAP_DS *eap_ds_alloc(void)
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) {
85 if ((eap_ds->request = eap_packet_alloc()) == NULL) {
93 void eap_ds_free(EAP_DS **eap_ds_p)
97 if (!eap_ds_p) return;
102 if (eap_ds->response) eap_packet_free(&(eap_ds->response));
103 if (eap_ds->request) eap_packet_free(&(eap_ds->request));
110 * Allocate a new EAP_HANDLER
112 EAP_HANDLER *eap_handler_alloc(void)
114 EAP_HANDLER *handler;
116 handler = rad_malloc(sizeof(EAP_HANDLER));
117 memset(handler, 0, sizeof(EAP_HANDLER));
121 void eap_handler_free(EAP_HANDLER *handler)
126 if (handler->identity) {
127 free(handler->identity);
128 handler->identity = NULL;
131 if (handler->prev_eapds) eap_ds_free(&(handler->prev_eapds));
132 if (handler->eap_ds) eap_ds_free(&(handler->eap_ds));
134 if ((handler->opaque) && (handler->free_opaque)) {
135 handler->free_opaque(handler->opaque);
136 handler->opaque = NULL;
138 else if ((handler->opaque) && (handler->free_opaque == NULL))
139 radlog(L_ERR, "Possible memory leak ...");
141 handler->opaque = NULL;
142 handler->free_opaque = NULL;
147 void eaptype_free(EAP_TYPES *i)
149 if (i->type->detach) (i->type->detach)(i->type_data);
151 if (i->handle) lt_dlclose(i->handle);
155 void eaplist_free(rlm_eap_t *inst)
157 EAP_HANDLER *node, *next;
159 for (node = inst->session_head; node != NULL; node = next) {
161 eap_handler_free(node);
164 inst->session_head = inst->session_tail = NULL;
168 * Add a handler to the set of active sessions.
170 * Since we're adding it to the list, we guess that this means
171 * the packet needs a State attribute. So add one.
173 int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
178 rad_assert(handler != NULL);
179 rad_assert(handler->request != NULL);
182 * Generate State, since we've been asked to add it to
185 state = generate_state(handler->request->timestamp);
186 pairadd(&(handler->request->reply->vps), state);
189 * Create a unique 'key' for the handler, based
190 * on State, Client-IP-Address, and EAP ID.
192 rad_assert(state->length == EAP_STATE_LEN);
195 * The time at which this request was made was the time
196 * at which it was received by the RADIUS server.
198 handler->timestamp = handler->request->timestamp;
201 memcpy(handler->state, state->vp_strvalue, sizeof(handler->state));
202 handler->src_ipaddr = handler->request->packet->src_ipaddr;
203 handler->eap_id = handler->eap_ds->request->id;
206 * We don't need this any more.
208 handler->request = NULL;
211 * Playing with a data structure shared among threads
212 * means that we need a lock, to avoid conflict.
214 pthread_mutex_lock(&(inst->session_mutex));
219 status = rbtree_insert(inst->session_tree, handler);
224 prev = inst->session_tail;
226 prev->next = handler;
227 handler->prev = prev;
228 handler->next = NULL;
229 inst->session_tail = handler;
231 inst->session_head = inst->session_tail = handler;
232 handler->next = handler->prev = NULL;
237 * Now that we've finished mucking with the list,
240 pthread_mutex_unlock(&(inst->session_mutex));
243 radlog(L_ERR, "rlm_eap: Failed to remember handler!");
244 eap_handler_free(handler);
252 * Find a a previous EAP-Request sent by us, which matches
253 * the current EAP-Response.
255 * Then, release the handle from the list, and return it to
258 * Also since we fill the eap_ds with the present EAP-Response we
259 * got to free the prev_eapds & move the eap_ds to prev_eapds
261 EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request,
262 eap_packet_t *eap_packet)
267 EAP_HANDLER *handler, myHandler;
270 * We key the sessions off of the 'state' attribute, so it
273 state = pairfind(request->packet->vps, PW_STATE);
275 (state->length != EAP_STATE_LEN)) {
279 myHandler.src_ipaddr = request->packet->src_ipaddr;
280 myHandler.eap_id = eap_packet->id;
281 memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state));
284 * Playing with a data structure shared among threads
285 * means that we need a lock, to avoid conflict.
287 pthread_mutex_lock(&(inst->session_mutex));
290 * Check the first few handlers in the list, and delete
291 * them if they're too old. We don't need to check them
292 * all, as incoming requests will quickly cause older
293 * handlers to be deleted.
296 for (i = 0; i < 2; i++) {
297 handler = inst->session_head;
299 ((request->timestamp - handler->timestamp) > inst->timer_limit)) {
300 node = rbtree_find(inst->session_tree, handler);
301 rad_assert(node != NULL);
302 rbtree_delete(inst->session_tree, node);
304 inst->session_head = handler->next;
305 if (handler->next) handler->next->prev = NULL;
306 eap_handler_free(handler);
311 node = rbtree_find(inst->session_tree, &myHandler);
313 handler = rbtree_node2data(inst->session_tree, node);
316 * Check against replays. The client can re-play
317 * a State attribute verbatim, so we wish to
318 * ensure that the attribute falls within the
319 * valid time window, which is the second at
320 * which it was sent out.
322 * Hmm... I'm not sure that this step is
323 * necessary, or even that it does anything.
325 if (verify_state(state, handler->timestamp) != 0) {
329 * It's OK, delete it from the tree.
331 rbtree_delete(inst->session_tree, node);
334 * And unsplice it from the linked list.
337 handler->prev->next = handler->next;
339 inst->session_head = handler->next;
342 handler->next->prev = handler->prev;
344 inst->session_tail = handler->prev;
346 handler->prev = handler->next = NULL;
350 pthread_mutex_unlock(&(inst->session_mutex));
356 DEBUG2(" rlm_eap: Request not found in the list");
361 * Found, but state verification failed.
364 radlog(L_ERR, "rlm_eap: State verification failed.");
368 DEBUG2(" rlm_eap: Request found, released from the list");
371 * Remember what the previous request was.
373 eap_ds_free(&(handler->prev_eapds));
374 handler->prev_eapds = handler->eap_ds;
375 handler->eap_ds = NULL;