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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000,2001 The FreeRADIUS server project
21 * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
27 * Allocate a new EAP_PACKET
29 EAP_PACKET *eap_packet_alloc(void)
33 rp = rad_malloc(sizeof(EAP_PACKET));
34 memset(rp, 0, sizeof(EAP_PACKET));
41 void eap_packet_free(EAP_PACKET **eap_packet_ptr)
43 EAP_PACKET *eap_packet;
45 if (!eap_packet_ptr) return;
46 eap_packet = *eap_packet_ptr;
47 if (!eap_packet) return;
49 if (eap_packet->type.data) {
51 * This is just a pointer in the packet
52 * so we do not free it but we NULL it
53 free(eap_packet->type.data);
55 eap_packet->type.data = NULL;
58 if (eap_packet->packet) {
59 free(eap_packet->packet);
60 eap_packet->packet = NULL;
65 *eap_packet_ptr = NULL;
69 * Allocate a new EAP_PACKET
71 EAP_DS *eap_ds_alloc(void)
75 eap_ds = rad_malloc(sizeof(EAP_DS));
76 memset(eap_ds, 0, sizeof(EAP_DS));
77 if ((eap_ds->response = eap_packet_alloc()) == NULL) {
81 if ((eap_ds->request = eap_packet_alloc()) == NULL) {
89 void eap_ds_free(EAP_DS **eap_ds_p)
93 if (!eap_ds_p) return;
98 if (eap_ds->response) eap_packet_free(&(eap_ds->response));
99 if (eap_ds->request) eap_packet_free(&(eap_ds->request));
106 * Allocate a new EAP_HANDLER
108 EAP_HANDLER *eap_handler_alloc(void)
110 EAP_HANDLER *handler;
112 handler = rad_malloc(sizeof(EAP_HANDLER));
113 memset(handler, 0, sizeof(EAP_HANDLER));
117 void eap_handler_free(EAP_HANDLER **handler_p)
119 EAP_HANDLER *handler;
121 if ((handler_p == NULL) || (*handler_p == NULL))
124 handler = *handler_p;
125 if (handler->identity) {
126 free(handler->identity);
127 handler->identity = NULL;
130 if (handler->username) pairfree(&(handler->username));
132 if (handler->prev_eapds) eap_ds_free(&(handler->prev_eapds));
133 if (handler->eap_ds) eap_ds_free(&(handler->eap_ds));
135 if ((handler->opaque) && (handler->free_opaque)) {
136 handler->free_opaque(handler->opaque);
137 handler->opaque = NULL;
139 else if ((handler->opaque) && (handler->free_opaque == NULL))
140 radlog(L_ERR, "Possible memory leak ...");
142 handler->opaque = NULL;
143 handler->free_opaque = NULL;
144 handler->next = NULL;
150 void eaptype_free(EAP_TYPES *i)
152 if (i->type->detach) (i->type->detach)(i->type_data);
154 if (i->handle) lt_dlclose(i->handle);
157 void eaplist_free(rlm_eap_t *inst)
162 * The sessions are split out into an array, which makes
163 * looking them up a bit faster.
165 for (i = 0; i < 256; i++) {
166 EAP_HANDLER *node, *next;
168 if (inst->sessions[i]) continue;
170 node = inst->sessions[i];
173 eap_handler_free(&node);
177 inst->sessions[i] = NULL;
182 * Add a handler to the set of active sessions.
184 * Since we're adding it to the list, we guess that this means
185 * the packet needs a State attribute. So add one.
187 int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
192 rad_assert(handler != NULL);
193 rad_assert(handler->request != NULL);
196 * Generate State, since we've been asked to add it to
199 state = generate_state(handler->request->timestamp);
200 pairadd(&(handler->request->reply->vps), state);
203 * Create a unique 'key' for the handler, based
204 * on State, Client-IP-Address, and EAP ID.
206 rad_assert(state->length == EAP_STATE_LEN);
208 memcpy(handler->state, state->strvalue, sizeof(handler->state));
209 handler->src_ipaddr = handler->request->packet->src_ipaddr;
210 handler->eap_id = handler->eap_ds->request->id;
213 * We key the array based on the challenge, which is
214 * a random number. This "fans out" the sessions, and
215 * helps to minimize the amount of work we've got to do
218 last = &(inst->sessions[state->strvalue[0]]);
219 while (*last) last = &((*last)->next);
222 * The time at which this request was made was the time
223 * at which it was received by the RADIUS server.
225 handler->timestamp = handler->request->timestamp;
227 handler->next = NULL;
230 * We don't need this any more.
232 handler->request = NULL;
239 * Find a a previous EAP-Request sent by us, which matches
240 * the current EAP-Response.
242 * Then, release the handle from the list, and return it to
245 * Also since we fill the eap_ds with the present EAP-Response we
246 * got to free the prev_eapds & move the eap_ds to prev_eapds
248 EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request, int eap_id)
250 EAP_HANDLER *node, *next, *ret = NULL;
252 EAP_HANDLER **first, **last;
255 * We key the sessions off of the 'state' attribute, so it
258 state = pairfind(request->packet->vps, PW_STATE);
260 (state->length != EAP_STATE_LEN)) {
264 last = first = &(inst->sessions[state->strvalue[0]]);
266 for (node = *first; node; node = next) {
270 * If the time on this entry has expired,
271 * delete it. We do this while walking the list,
272 * in order to spread out the work of deleting old
275 if ((request->timestamp - node->timestamp) > inst->timer_limit) {
277 eap_handler_free(&node);
282 * Find the previous part of the same conversation,
283 * keying off of the EAP ID, the client IP, and
284 * the State attribute.
286 * If we've found a conversation, then we don't
287 * have to check entries later in the list for
288 * timeout, as they're guaranteed to be newer than
291 if ((node->eap_id == eap_id) &&
292 (node->src_ipaddr == request->packet->src_ipaddr) &&
293 (memcmp(node->state, state->strvalue, state->length) == 0)) {
295 * Check against replays. The client can
296 * re-play a State attribute verbatim, so
297 * we wish to ensure that the attribute falls
298 * within the valid time window, which is
299 * the second at which it was sent out.
301 if (verify_state(state, node->timestamp) != 0) {
302 radlog(L_ERR, "rlm_eap: State verification failed.");
306 DEBUG2(" rlm_eap: Request found, released from the list");
308 * detach the node from the list
314 * Don't bother updating handler->request, etc.
315 * eap_handler() will do that for us.
319 * Remember what the previous request was.
321 eap_ds_free(&(node->prev_eapds));
322 node->prev_eapds = node->eap_ds;
326 * And return it to the caller.
330 last = &(node->next);
335 DEBUG2(" rlm_eap: Request not found in the list");