Avoid memory leak when sending RADIUS accounting start message failed
[strongswan.git] / src / libcharon / plugins / tnc_pdp / tnc_pdp_connections.c
1 /*
2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tnc_pdp_connections.h"
17
18 #include <utils/linked_list.h>
19 #include <debug.h>
20
21 typedef struct private_tnc_pdp_connections_t private_tnc_pdp_connections_t;
22 typedef struct entry_t entry_t;
23
24 /**
25 * Private data of tnc_pdp_connections_t
26 */
27 struct private_tnc_pdp_connections_t {
28
29 /**
30 * Implements tnc_pdp_connections_t interface
31 */
32 tnc_pdp_connections_t public;
33
34 /**
35 * List of TNC PEP RADIUS Connections
36 */
37 linked_list_t *list;
38 };
39
40 /**
41 * Data entry for a TNC PEP RADIUS connection
42 */
43 struct entry_t {
44
45 /**
46 * NAS identifier of PEP
47 */
48 chunk_t nas_id;
49
50 /**
51 * User name of TNC Client
52 */
53 chunk_t user_name;
54
55 /**
56 * EAP method state
57 */
58 eap_method_t *method;
59
60 /**
61 * IKE SA used for bus communication
62 */
63 ike_sa_t *ike_sa;
64 };
65
66 /**
67 * Free the memory allocated to a data entry
68 */
69 static void free_entry(entry_t *this)
70 {
71 this->method->destroy(this->method);
72 this->ike_sa->destroy(this->ike_sa);
73 free(this->nas_id.ptr);
74 free(this->user_name.ptr);
75 free(this);
76 }
77
78 /**
79 * Find a matching data entry
80 */
81 static bool equals_entry( entry_t *this, chunk_t nas_id, chunk_t user_name)
82 {
83 bool no_nas_id = !this->nas_id.ptr && !nas_id.ptr;
84
85 return (chunk_equals(this->nas_id, nas_id) || no_nas_id) &&
86 chunk_equals(this->user_name, user_name);
87 }
88
89 /**
90 * Find a matching data entry
91 */
92 static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op)
93 {
94 if (nas_id.len)
95 {
96 DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s' NAS '%.*s'",
97 not ? "could not find" : op, user_name.len, user_name.ptr,
98 nas_id.len, nas_id.ptr);
99 }
100 else
101 {
102 DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'",
103 not ? "could not find" : op, user_name.len, user_name.ptr);
104 }
105 }
106
107 METHOD(tnc_pdp_connections_t, add, void,
108 private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
109 identification_t *peer, eap_method_t *method)
110 {
111 enumerator_t *enumerator;
112 entry_t *entry;
113 ike_sa_id_t *ike_sa_id;
114 ike_sa_t *ike_sa;
115 bool found = FALSE;
116
117 ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, 0, 0, FALSE);
118 ike_sa = ike_sa_create(ike_sa_id, FALSE, IKEV2);
119 ike_sa_id->destroy(ike_sa_id);
120 ike_sa->set_other_id(ike_sa, peer);
121
122 enumerator = this->list->create_enumerator(this->list);
123 while (enumerator->enumerate(enumerator, &entry))
124 {
125 if (equals_entry(entry, nas_id, user_name))
126 {
127 found = TRUE;
128 entry->method->destroy(entry->method);
129 entry->ike_sa->destroy(entry->ike_sa);
130 DBG1(DBG_CFG, "removed stale RADIUS connection");
131 entry->method = method;
132 entry->ike_sa = ike_sa;
133 break;
134 }
135 }
136 enumerator->destroy(enumerator);
137
138 if (!found)
139 {
140 entry = malloc_thing(entry_t);
141 entry->nas_id = chunk_clone(nas_id);
142 entry->user_name = chunk_clone(user_name);
143 entry->method = method;
144 entry->ike_sa = ike_sa;
145 this->list->insert_last(this->list, entry);
146 }
147 dbg_nas_user(nas_id, user_name, FALSE, "created");
148 }
149
150 METHOD(tnc_pdp_connections_t, remove_, void,
151 private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name)
152 {
153 enumerator_t *enumerator;
154 entry_t *entry;
155
156 enumerator = this->list->create_enumerator(this->list);
157 while (enumerator->enumerate(enumerator, &entry))
158 {
159 if (equals_entry(entry, nas_id, user_name))
160 {
161 free_entry(entry);
162 this->list->remove_at(this->list, enumerator);
163 dbg_nas_user(nas_id, user_name, FALSE, "removed");
164 break;
165 }
166 }
167 enumerator->destroy(enumerator);
168 }
169
170 METHOD(tnc_pdp_connections_t, get_state, eap_method_t*,
171 private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
172 ike_sa_t **ike_sa)
173 {
174 enumerator_t *enumerator;
175 entry_t *entry;
176 eap_method_t *found = NULL;
177
178 enumerator = this->list->create_enumerator(this->list);
179 while (enumerator->enumerate(enumerator, &entry))
180 {
181 if (equals_entry(entry, nas_id, user_name))
182 {
183 found = entry->method;
184 *ike_sa = entry->ike_sa;
185 break;
186 }
187 }
188 enumerator->destroy(enumerator);
189
190 dbg_nas_user(nas_id, user_name, !found, "found");
191 return found;
192 }
193
194 METHOD(tnc_pdp_connections_t, destroy, void,
195 private_tnc_pdp_connections_t *this)
196 {
197 this->list->destroy_function(this->list, (void*)free_entry);
198 free(this);
199 }
200
201 /*
202 * see header file
203 */
204 tnc_pdp_connections_t *tnc_pdp_connections_create(void)
205 {
206 private_tnc_pdp_connections_t *this;
207
208 INIT(this,
209 .public = {
210 .add = _add,
211 .remove = _remove_,
212 .get_state = _get_state,
213 .destroy = _destroy,
214 },
215 .list = linked_list_create(),
216 );
217
218 return &this->public;
219 }
220