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