moved tnc_imv plugin to libtnccs thanks to recommendation callback function
[strongswan.git] / src / libtnccs / plugins / tnc_imv / tnc_imv.c
1 /*
2 * Copyright (C) 2010-2013 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_imv.h"
17
18 #include <dlfcn.h>
19
20 #include <tncif_pa_subtypes.h>
21
22 #include <utils/debug.h>
23 #include <library.h>
24 #include <collections/linked_list.h>
25 #include <threading/mutex.h>
26
27 typedef struct private_tnc_imv_t private_tnc_imv_t;
28
29 /**
30 * Private data of an imv_t object.
31 */
32 struct private_tnc_imv_t {
33
34 /**
35 * Public members of imv_t.
36 */
37 imv_t public;
38
39 /**
40 * Name of loaded IMV
41 */
42 char *name;
43
44 /**
45 * Handle of loaded IMV
46 */
47 void *handle;
48
49 /**
50 * ID of loaded IMV
51 */
52 TNC_IMVID id;
53
54 /**
55 * List of additional IMV IDs
56 */
57 linked_list_t *additional_ids;
58
59 /**
60 * List of message types supported by IMV - Vendor ID part
61 */
62 TNC_VendorIDList supported_vids;
63
64 /**
65 * List of message types supported by IMV - Subtype part
66 */
67 TNC_MessageSubtypeList supported_subtypes;
68
69 /**
70 * Number of supported message types
71 */
72 TNC_UInt32 type_count;
73
74 /**
75 * mutex to lock the imv_t object
76 */
77 mutex_t *mutex;
78 };
79
80 METHOD(imv_t, set_id, void,
81 private_tnc_imv_t *this, TNC_IMVID id)
82 {
83 this->id = id;
84 }
85
86 METHOD(imv_t, get_id, TNC_IMVID,
87 private_tnc_imv_t *this)
88 {
89 return this->id;
90 }
91
92 METHOD(imv_t, add_id, void,
93 private_tnc_imv_t *this, TNC_IMVID id)
94 {
95 TNC_IMVID *new_id;
96
97 new_id = malloc_thing(TNC_IMVID);
98 *new_id = id;
99 this->additional_ids->insert_last(this->additional_ids, new_id);
100 }
101
102 METHOD(imv_t, has_id, bool,
103 private_tnc_imv_t *this, TNC_IMVID id)
104 {
105 enumerator_t *enumerator;
106 TNC_IMVID *additional_id;
107 bool found = FALSE;
108
109 /* check primary IMV ID */
110 if (id == this->id)
111 {
112 return TRUE;
113 }
114
115 /* return if there are no additional IMV IDs */
116 if (this->additional_ids->get_count(this->additional_ids) == 0)
117 {
118 return FALSE;
119 }
120
121 /* check additional IMV IDs */
122 enumerator = this->additional_ids->create_enumerator(this->additional_ids);
123 while (enumerator->enumerate(enumerator, &additional_id))
124 {
125 if (id == *additional_id)
126 {
127 found = TRUE;
128 break;
129 }
130 }
131 enumerator->destroy(enumerator);
132
133 return found;
134 }
135
136 METHOD(imv_t, get_name, char*,
137 private_tnc_imv_t *this)
138 {
139 return this->name;
140 }
141
142 METHOD(imv_t, set_message_types, void,
143 private_tnc_imv_t *this, TNC_MessageTypeList supported_types,
144 TNC_UInt32 type_count)
145 {
146 char buf[BUF_LEN];
147 char *pos = buf;
148 int len = sizeof(buf);
149 int i, written;
150 size_t size;
151 TNC_VendorID vid;
152 TNC_MessageSubtype subtype;
153 enum_name_t *pa_subtype_names;
154
155 /* lock the imv_t instance */
156 this->mutex->lock(this->mutex);
157
158 /* Free existing VendorID and MessageSubtype lists */
159 free(this->supported_vids);
160 this->supported_vids = NULL;
161 free(this->supported_subtypes);
162 this->supported_subtypes = NULL;
163
164 /* Store the new MessageType list */
165 this->type_count = type_count;
166 if (type_count && supported_types)
167 {
168 size = type_count * sizeof(TNC_VendorID);
169 this->supported_vids = malloc(size);
170 size = type_count * sizeof(TNC_MessageSubtype);
171 this->supported_subtypes = malloc(size);
172
173 for (i = 0; i < type_count; i++)
174 {
175 vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY;
176 subtype = supported_types[i] & TNC_SUBTYPE_ANY;
177
178 pa_subtype_names = get_pa_subtype_names(vid);
179 if (pa_subtype_names)
180 {
181 written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x",
182 pen_names, vid, pa_subtype_names, subtype,
183 vid, subtype);
184 }
185 else
186 {
187 written = snprintf(pos, len," '%N' 0x%06x/0x%02x",
188 pen_names, vid, vid, subtype);
189 }
190 if (written >= len)
191 {
192 break;
193 }
194 pos += written;
195 len -= written;
196
197 this->supported_vids[i] = vid;
198 this->supported_subtypes[i] = subtype;
199 }
200 }
201 *pos = '\0';
202 DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
203 this->id, type_count, (type_count == 1) ? "":"s", buf);
204
205 /* unlock the imv_t instance */
206 this->mutex->unlock(this->mutex);
207 }
208
209 METHOD(imv_t, set_message_types_long, void,
210 private_tnc_imv_t *this, TNC_VendorIDList supported_vids,
211 TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count)
212 {
213 char buf[BUF_LEN];
214 char *pos = buf;
215 int len = sizeof(buf);
216 int i, written;
217 size_t size;
218 TNC_VendorID vid;
219 TNC_MessageSubtype subtype;
220 enum_name_t *pa_subtype_names;
221
222 /* lock the imv_t instance */
223 this->mutex->lock(this->mutex);
224
225 /* Free existing VendorID and MessageSubtype lists */
226 free(this->supported_vids);
227 this->supported_vids = NULL;
228 free(this->supported_subtypes);
229 this->supported_subtypes = NULL;
230
231 /* Store the new MessageType list */
232 this->type_count = type_count;
233 if (type_count && supported_vids && supported_subtypes)
234 {
235 size = type_count * sizeof(TNC_VendorID);
236 this->supported_vids = malloc(size);
237 memcpy(this->supported_vids, supported_vids, size);
238 size = type_count * sizeof(TNC_MessageSubtype);
239 this->supported_subtypes = malloc(size);
240 memcpy(this->supported_subtypes, supported_subtypes, size);
241
242 for (i = 0; i < type_count; i++)
243 {
244 vid = supported_vids[i];
245 subtype = supported_subtypes[i];
246
247 pa_subtype_names = get_pa_subtype_names(vid);
248 if (pa_subtype_names)
249 {
250 written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x",
251 pen_names, vid, pa_subtype_names, subtype,
252 vid, subtype);
253 }
254 else
255 {
256 written = snprintf(pos, len," '%N' 0x%06x/0x%08x",
257 pen_names, vid, vid, subtype);
258 }
259 if (written >= len)
260 {
261 break;
262 }
263 pos += written;
264 len -= written;
265 }
266 }
267 *pos = '\0';
268 DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
269 this->id, type_count, (type_count == 1) ? "":"s", buf);
270
271 /* unlock the imv_t instance */
272 this->mutex->unlock(this->mutex);
273 }
274
275 METHOD(imv_t, type_supported, bool,
276 private_tnc_imv_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype)
277 {
278 TNC_VendorID vid;
279 TNC_MessageSubtype subtype;
280 int i;
281
282 for (i = 0; i < this->type_count; i++)
283 {
284 vid = this->supported_vids[i];
285 subtype = this->supported_subtypes[i];
286
287 if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) ||
288 (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY ||
289 subtype == msg_subtype)))
290 {
291 return TRUE;
292 }
293 }
294 return FALSE;
295 }
296
297 METHOD(imv_t, destroy, void,
298 private_tnc_imv_t *this)
299 {
300 if (this->handle && lib->settings->get_bool(lib->settings,
301 "libtnccs.plugins.tnc-imv.dlclose", TRUE))
302 {
303 dlclose(this->handle);
304 }
305 this->mutex->destroy(this->mutex);
306 this->additional_ids->destroy_function(this->additional_ids, free);
307 free(this->supported_vids);
308 free(this->supported_subtypes);
309 free(this->name);
310 free(this);
311 }
312
313 /**
314 * Generic constructor.
315 */
316 static private_tnc_imv_t* tnc_imv_create_empty(char *name)
317 {
318 private_tnc_imv_t *this;
319
320 INIT(this,
321 .public = {
322 .set_id = _set_id,
323 .get_id = _get_id,
324 .add_id = _add_id,
325 .has_id = _has_id,
326 .get_name = _get_name,
327 .set_message_types = _set_message_types,
328 .set_message_types_long = _set_message_types_long,
329 .type_supported = _type_supported,
330 .destroy = _destroy,
331 },
332 .name = strdup(name),
333 .additional_ids = linked_list_create(),
334 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
335 );
336
337 return this;
338 }
339
340 /**
341 * Described in header.
342 */
343 imv_t* tnc_imv_create(char *name, char *path)
344 {
345 private_tnc_imv_t *this;
346
347 this = tnc_imv_create_empty(name);
348
349 this->handle = dlopen(path, RTLD_LAZY);
350 if (!this->handle)
351 {
352 DBG1(DBG_TNC, "IMV \"%s\" failed to load: %s", name, dlerror());
353 destroy(this);
354 return NULL;
355 }
356
357 this->public.initialize = dlsym(this->handle, "TNC_IMV_Initialize");
358 if (!this->public.initialize)
359 {
360 DBG1(DBG_TNC, "could not resolve TNC_IMV_Initialize in %s: %s\n",
361 path, dlerror());
362 destroy(this);
363 return NULL;
364 }
365 this->public.notify_connection_change =
366 dlsym(this->handle, "TNC_IMV_NotifyConnectionChange");
367 this->public.solicit_recommendation =
368 dlsym(this->handle, "TNC_IMV_SolicitRecommendation");
369 if (!this->public.solicit_recommendation)
370 {
371 DBG1(DBG_TNC, "could not resolve TNC_IMV_SolicitRecommendation in %s: %s\n",
372 path, dlerror());
373 destroy(this);
374 return NULL;
375 }
376 this->public.receive_message =
377 dlsym(this->handle, "TNC_IMV_ReceiveMessage");
378 this->public.receive_message_long =
379 dlsym(this->handle, "TNC_IMV_ReceiveMessageLong");
380 this->public.batch_ending =
381 dlsym(this->handle, "TNC_IMV_BatchEnding");
382 this->public.terminate =
383 dlsym(this->handle, "TNC_IMV_Terminate");
384 this->public.provide_bind_function =
385 dlsym(this->handle, "TNC_IMV_ProvideBindFunction");
386 if (!this->public.provide_bind_function)
387 {
388 DBG1(DBG_TNC, "could not resolve TNC_IMV_ProvideBindFunction in %s: %s\n",
389 path, dlerror());
390 destroy(this);
391 return NULL;
392 }
393
394 return &this->public;
395 }
396
397 /**
398 * Described in header.
399 */
400 imv_t* tnc_imv_create_from_functions(char *name,
401 TNC_IMV_InitializePointer initialize,
402 TNC_IMV_NotifyConnectionChangePointer notify_connection_change,
403 TNC_IMV_ReceiveMessagePointer receive_message,
404 TNC_IMV_ReceiveMessageLongPointer receive_message_long,
405 TNC_IMV_SolicitRecommendationPointer solicit_recommendation,
406 TNC_IMV_BatchEndingPointer batch_ending,
407 TNC_IMV_TerminatePointer terminate,
408 TNC_IMV_ProvideBindFunctionPointer provide_bind_function)
409 {
410 private_tnc_imv_t *this;
411
412 this = tnc_imv_create_empty(name);
413
414 this->public.initialize = initialize;
415 this->public.notify_connection_change = notify_connection_change;
416 this->public.receive_message = receive_message;
417 this->public.receive_message_long = receive_message_long;
418 this->public.solicit_recommendation = solicit_recommendation;
419 this->public.batch_ending = batch_ending;
420 this->public.terminate = terminate;
421 this->public.provide_bind_function = provide_bind_function;
422
423 return &this->public;
424 }