added IMC and IMV IDs as arguments to send_message()
[strongswan.git] / src / libcharon / tnc / tnccs / tnccs_manager.c
1 /*
2 * Copyright (C) 2010 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 "tnccs_manager.h"
17
18 #include <tnc/imv/imv_recommendations.h>
19
20 #include <debug.h>
21 #include <daemon.h>
22 #include <utils/linked_list.h>
23 #include <threading/rwlock.h>
24
25 typedef struct private_tnccs_manager_t private_tnccs_manager_t;
26 typedef struct tnccs_entry_t tnccs_entry_t;
27 typedef struct tnccs_connection_entry_t tnccs_connection_entry_t;
28
29 /**
30 * TNCCS constructor entry
31 */
32 struct tnccs_entry_t {
33
34 /**
35 * TNCCS protocol type
36 */
37 tnccs_type_t type;
38
39 /**
40 * constructor function to create instance
41 */
42 tnccs_constructor_t constructor;
43 };
44
45 /**
46 * TNCCS connection entry
47 */
48 struct tnccs_connection_entry_t {
49
50 /**
51 * TNCCS connection ID
52 */
53 TNC_ConnectionID id;
54
55 /**
56 * TNCCS instance
57 */
58 tnccs_t *tnccs;
59
60 /**
61 * TNCCS send message function
62 */
63 tnccs_send_message_t send_message;
64
65 /**
66 * collection of IMV recommendations
67 */
68 recommendations_t *recs;
69 };
70
71 /**
72 * private data of tnccs_manager
73 */
74 struct private_tnccs_manager_t {
75
76 /**
77 * public functions
78 */
79 tnccs_manager_t public;
80
81 /**
82 * list of TNCCS protocol entries
83 */
84 linked_list_t *protocols;
85
86 /**
87 * rwlock to lock the TNCCS protocol entries
88 */
89 rwlock_t *protocol_lock;
90
91 /**
92 * connection ID counter
93 */
94 TNC_ConnectionID connection_id;
95
96 /**
97 * list of TNCCS connection entries
98 */
99 linked_list_t *connections;
100
101 /**
102 * rwlock to lock TNCCS connection entries
103 */
104 rwlock_t *connection_lock;
105
106 };
107
108 METHOD(tnccs_manager_t, add_method, void,
109 private_tnccs_manager_t *this, tnccs_type_t type,
110 tnccs_constructor_t constructor)
111 {
112 tnccs_entry_t *entry;
113
114 entry = malloc_thing(tnccs_entry_t);
115 entry->type = type;
116 entry->constructor = constructor;
117
118 this->protocol_lock->write_lock(this->protocol_lock);
119 this->protocols->insert_last(this->protocols, entry);
120 this->protocol_lock->unlock(this->protocol_lock);
121 }
122
123 METHOD(tnccs_manager_t, remove_method, void,
124 private_tnccs_manager_t *this, tnccs_constructor_t constructor)
125 {
126 enumerator_t *enumerator;
127 tnccs_entry_t *entry;
128
129 this->protocol_lock->write_lock(this->protocol_lock);
130 enumerator = this->protocols->create_enumerator(this->protocols);
131 while (enumerator->enumerate(enumerator, &entry))
132 {
133 if (constructor == entry->constructor)
134 {
135 this->protocols->remove_at(this->protocols, enumerator);
136 free(entry);
137 }
138 }
139 enumerator->destroy(enumerator);
140 this->protocol_lock->unlock(this->protocol_lock);
141 }
142
143 METHOD(tnccs_manager_t, create_instance, tnccs_t*,
144 private_tnccs_manager_t *this, tnccs_type_t type, bool is_server)
145 {
146 enumerator_t *enumerator;
147 tnccs_entry_t *entry;
148 tnccs_t *protocol = NULL;
149
150 this->protocol_lock->read_lock(this->protocol_lock);
151 enumerator = this->protocols->create_enumerator(this->protocols);
152 while (enumerator->enumerate(enumerator, &entry))
153 {
154 if (type == entry->type)
155 {
156 protocol = entry->constructor(is_server);
157 if (protocol)
158 {
159 break;
160 }
161 }
162 }
163 enumerator->destroy(enumerator);
164 this->protocol_lock->unlock(this->protocol_lock);
165
166 return protocol;
167 }
168
169 METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
170 private_tnccs_manager_t *this, tnccs_t *tnccs,
171 tnccs_send_message_t send_message, recommendations_t **recs)
172 {
173 tnccs_connection_entry_t *entry;
174
175 entry = malloc_thing(tnccs_connection_entry_t);
176 entry->tnccs = tnccs;
177 entry->send_message = send_message;
178 if (recs)
179 {
180 /* we assume a TNC Server needing recommendations from IMVs */
181 if (!charon->imvs)
182 {
183 DBG1(DBG_TNC, "no IMV manager available!");
184 free(entry);
185 return 0;
186 }
187 entry->recs = charon->imvs->create_recommendations(charon->imvs);
188 *recs = entry->recs;
189 }
190 else
191 {
192 /* we assume a TNC Client */
193 if (!charon->imcs)
194 {
195 DBG1(DBG_TNC, "no IMC manager available!");
196 free(entry);
197 return 0;
198 }
199 entry->recs = NULL;
200 }
201 this->connection_lock->write_lock(this->connection_lock);
202 entry->id = ++this->connection_id;
203 this->connections->insert_last(this->connections, entry);
204 this->connection_lock->unlock(this->connection_lock);
205
206 DBG1(DBG_TNC, "assigned TNCCS Connection ID %u", entry->id);
207 return entry->id;
208 }
209
210 METHOD(tnccs_manager_t, remove_connection, void,
211 private_tnccs_manager_t *this, TNC_ConnectionID id)
212 {
213 enumerator_t *enumerator;
214 tnccs_connection_entry_t *entry;
215
216 this->connection_lock->write_lock(this->connection_lock);
217 enumerator = this->connections->create_enumerator(this->connections);
218 while (enumerator->enumerate(enumerator, &entry))
219 {
220 if (id == entry->id)
221 {
222 this->connections->remove_at(this->connections, enumerator);
223 if (entry->recs)
224 {
225 entry->recs->destroy(entry->recs);
226 }
227 free(entry);
228 DBG1(DBG_TNC, "removed TNCCS Connection ID %u", id);
229 }
230 }
231 enumerator->destroy(enumerator);
232 this->connection_lock->unlock(this->connection_lock);
233 }
234
235 METHOD(tnccs_manager_t, send_message, TNC_Result,
236 private_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id,
237 TNC_ConnectionID id,
238 TNC_BufferReference msg,
239 TNC_UInt32 msg_len,
240 TNC_MessageType msg_type)
241 {
242 enumerator_t *enumerator;
243 tnccs_connection_entry_t *entry;
244 tnccs_send_message_t send_message = NULL;
245 tnccs_t *tnccs = NULL;
246
247 this->connection_lock->read_lock(this->connection_lock);
248 enumerator = this->connections->create_enumerator(this->connections);
249 while (enumerator->enumerate(enumerator, &entry))
250 {
251 if (id == entry->id)
252 {
253 tnccs = entry->tnccs;
254 send_message = entry->send_message;
255 break;
256 }
257 }
258 enumerator->destroy(enumerator);
259 this->connection_lock->unlock(this->connection_lock);
260
261 if (tnccs && send_message)
262 {
263 send_message(tnccs, imc_id, imv_id, msg, msg_len, msg_type);
264 return TNC_RESULT_SUCCESS;
265 }
266 return TNC_RESULT_FATAL;
267 }
268
269 METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
270 private_tnccs_manager_t *this, TNC_IMVID imv_id,
271 TNC_ConnectionID id,
272 TNC_IMV_Action_Recommendation rec,
273 TNC_IMV_Evaluation_Result eval)
274 {
275 enumerator_t *enumerator;
276 tnccs_connection_entry_t *entry;
277 recommendations_t *recs = NULL;
278
279 this->connection_lock->read_lock(this->connection_lock);
280 enumerator = this->connections->create_enumerator(this->connections);
281 while (enumerator->enumerate(enumerator, &entry))
282 {
283 if (id == entry->id)
284 {
285 recs = entry->recs;
286 break;
287 }
288 }
289 enumerator->destroy(enumerator);
290 this->connection_lock->unlock(this->connection_lock);
291
292 if (recs)
293 {
294 recs->provide_recommendation(recs, imv_id, rec, eval);
295 return TNC_RESULT_SUCCESS;
296 }
297 return TNC_RESULT_FATAL;
298 }
299
300 METHOD(tnccs_manager_t, get_attribute, TNC_Result,
301 private_tnccs_manager_t *this, TNC_IMVID imv_id,
302 TNC_ConnectionID id,
303 TNC_AttributeID attribute_id,
304 TNC_UInt32 buffer_len,
305 TNC_BufferReference buffer,
306 TNC_UInt32 *out_value_len)
307 {
308 enumerator_t *enumerator;
309 tnccs_connection_entry_t *entry;
310 recommendations_t *recs = NULL;
311
312 if (id == TNC_CONNECTIONID_ANY ||
313 attribute_id != TNC_ATTRIBUTEID_PREFERRED_LANGUAGE)
314 {
315 return TNC_RESULT_INVALID_PARAMETER;
316 }
317
318 this->connection_lock->read_lock(this->connection_lock);
319 enumerator = this->connections->create_enumerator(this->connections);
320 while (enumerator->enumerate(enumerator, &entry))
321 {
322 if (id == entry->id)
323 {
324 recs = entry->recs;
325 break;
326 }
327 }
328 enumerator->destroy(enumerator);
329 this->connection_lock->unlock(this->connection_lock);
330
331 if (recs)
332 {
333 chunk_t pref_lang;
334
335 pref_lang = recs->get_preferred_language(recs);
336 if (pref_lang.len == 0)
337 {
338 return TNC_RESULT_INVALID_PARAMETER;
339 }
340 *out_value_len = pref_lang.len;
341 if (buffer && buffer_len <= pref_lang.len)
342 {
343 memcpy(buffer, pref_lang.ptr, pref_lang.len);
344 }
345 return TNC_RESULT_SUCCESS;
346 }
347 return TNC_RESULT_INVALID_PARAMETER;
348 }
349
350 METHOD(tnccs_manager_t, set_attribute, TNC_Result,
351 private_tnccs_manager_t *this, TNC_IMVID imv_id,
352 TNC_ConnectionID id,
353 TNC_AttributeID attribute_id,
354 TNC_UInt32 buffer_len,
355 TNC_BufferReference buffer)
356 {
357 enumerator_t *enumerator;
358 tnccs_connection_entry_t *entry;
359 recommendations_t *recs = NULL;
360
361 if (id == TNC_CONNECTIONID_ANY ||
362 (attribute_id != TNC_ATTRIBUTEID_REASON_STRING &&
363 attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE))
364 {
365 return TNC_RESULT_INVALID_PARAMETER;
366 }
367
368 this->connection_lock->read_lock(this->connection_lock);
369 enumerator = this->connections->create_enumerator(this->connections);
370 while (enumerator->enumerate(enumerator, &entry))
371 {
372 if (id == entry->id)
373 {
374 recs = entry->recs;
375 break;
376 }
377 }
378 enumerator->destroy(enumerator);
379 this->connection_lock->unlock(this->connection_lock);
380
381 if (recs)
382 {
383 chunk_t attribute = { buffer, buffer_len };
384
385 if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING)
386 {
387 return recs->set_reason_string(recs, imv_id, attribute);
388 }
389 else
390 {
391 return recs->set_reason_language(recs, imv_id, attribute);
392 }
393 }
394 return TNC_RESULT_INVALID_PARAMETER;
395 }
396
397 METHOD(tnccs_manager_t, destroy, void,
398 private_tnccs_manager_t *this)
399 {
400 this->protocols->destroy_function(this->protocols, free);
401 this->protocol_lock->destroy(this->protocol_lock);
402 this->connections->destroy_function(this->connections, free);
403 this->connection_lock->destroy(this->connection_lock);
404 free(this);
405 }
406
407 /*
408 * See header
409 */
410 tnccs_manager_t *tnccs_manager_create()
411 {
412 private_tnccs_manager_t *this;
413
414 INIT(this,
415 .public = {
416 .add_method = _add_method,
417 .remove_method = _remove_method,
418 .create_instance = _create_instance,
419 .create_connection = _create_connection,
420 .remove_connection = _remove_connection,
421 .send_message = _send_message,
422 .provide_recommendation = _provide_recommendation,
423 .get_attribute = _get_attribute,
424 .set_attribute = _set_attribute,
425 .destroy = _destroy,
426 },
427 .protocols = linked_list_create(),
428 .connections = linked_list_create(),
429 .protocol_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
430 .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
431 );
432
433 return &this->public;
434 }
435