Annotation of embedaddon/strongswan/src/libimcv/plugins/imc_swima/imc_swima.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2017 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 "imc_swima_state.h"
17:
18: #include <imc/imc_agent.h>
19: #include <imc/imc_msg.h>
20: #include "ietf/swima/ietf_swima_attr_req.h"
21: #include "ietf/swima/ietf_swima_attr_sw_inv.h"
22: #include "ietf/swima/ietf_swima_attr_sw_ev.h"
23: #include "swima/swima_inventory.h"
24: #include "swima/swima_collector.h"
25: #include "swima/swima_error.h"
26: #include "tcg/seg/tcg_seg_attr_max_size.h"
27: #include "tcg/seg/tcg_seg_attr_seg_env.h"
28:
29: #include <tncif_pa_subtypes.h>
30: #include <pen/pen.h>
31: #include <utils/debug.h>
32:
33: #include <errno.h>
34: #include <poll.h>
35: #include <stdio.h>
36: #include <stdlib.h>
37: #include <sys/inotify.h>
38: #include <unistd.h>
39:
40: #ifndef SW_COLLECTOR
41: #define SW_COLLECTOR NULL
42: #endif
43:
44: /* IMC definitions */
45:
46: static const char imc_name[] = "SWIMA";
47:
48: static pen_type_t msg_types[] = {
49: { PEN_IETF, PA_SUBTYPE_IETF_SWIMA }
50: };
51:
52: static imc_agent_t *imc_swima;
53:
54: /**
55: * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
56: */
57: TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
58: TNC_Version min_version,
59: TNC_Version max_version,
60: TNC_Version *actual_version)
61: {
62: if (imc_swima)
63: {
64: DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
65: return TNC_RESULT_ALREADY_INITIALIZED;
66: }
67: imc_swima = imc_agent_create(imc_name, msg_types, countof(msg_types),
68: imc_id, actual_version);
69: if (!imc_swima)
70: {
71: return TNC_RESULT_FATAL;
72: }
73: if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
74: {
75: DBG1(DBG_IMC, "no common IF-IMC version");
76: return TNC_RESULT_NO_COMMON_VERSION;
77: }
78: return TNC_RESULT_SUCCESS;
79: }
80:
81: /**
82: * Poll for IN_CLOSE_WRITE event on the apt history.log
83: */
84: static bool poll_history_log(void)
85: {
86: int fd, wd, res;
87: nfds_t nfds;
88: struct pollfd fds[1];
89: char *history_path;
90: bool success = FALSE;
91:
92: history_path = lib->settings->get_str(lib->settings, "sw-collector.history",
93: NULL);
94: if (!history_path)
95: {
96: DBG1(DBG_IMC, "sw-collector.history path not set");
97: return FALSE;
98: }
99:
100: /* Create the file descriptor for accessing the inotify API */
101: fd = inotify_init1(IN_NONBLOCK);
102: if (fd == -1)
103: {
104: DBG1(DBG_IMC, "inotify file descriptor could not be created");
105: return FALSE;
106: }
107:
108: /* Watch for CLOSE_WRITE events on history log */
109: wd = inotify_add_watch(fd, history_path, IN_CLOSE_WRITE);
110: if (wd == -1)
111: {
112: DBG1(DBG_IMC, "cannot watch '%s'", history_path);
113: goto end;
114: }
115:
116: /* Prepare for polling */
117: nfds = 1;
118:
119: /* Inotify input */
120: fds[0].fd = fd;
121: fds[0].events = POLLIN;
122:
123: while (1)
124: {
125: DBG1(DBG_IMC, " waiting for write event on history.log ...");
126:
127: res = poll(fds, nfds, -1);
128: if (res == -1)
129: {
130: DBG1(DBG_IMC, " poll failed: %s", strerror(errno));
131: if (errno == EINTR)
132: {
133: continue;
134: }
135: goto end;
136: }
137: if (res > 0 && fds[0].revents & POLLIN)
138: {
139: DBG1(DBG_IMC, " poll successful");
140: success = TRUE;
141: break;
142: }
143: }
144:
145: end:
146: close(fd);
147: return success;
148: }
149:
150: /**
151: * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
152: */
153: TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
154: TNC_ConnectionID connection_id,
155: TNC_ConnectionState new_state)
156: {
157: imc_state_t *state;
158: imc_swima_state_t *swima_state;
159: imc_swima_subscription_t *subscription;
160: TNC_IMV_Evaluation_Result res;
161: TNC_Result result;
162: uint32_t eid, eid_epoch;
163:
164: if (!imc_swima)
165: {
166: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
167: return TNC_RESULT_NOT_INITIALIZED;
168: }
169: switch (new_state)
170: {
171: case TNC_CONNECTION_STATE_CREATE:
172: state = imc_swima_state_create(connection_id);
173: return imc_swima->create_state(imc_swima, state);
174: case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
175: case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
176: case TNC_CONNECTION_STATE_ACCESS_NONE:
177: /* get updated IMC state */
178: result = imc_swima->change_state(imc_swima, connection_id,
179: new_state, &state);
180: if (result != TNC_RESULT_SUCCESS)
181: {
182: return TNC_RESULT_FATAL;
183: }
184: swima_state = (imc_swima_state_t*)state;
185:
186: /* do a handshake retry? */
187: if (swima_state->get_subscription(swima_state, &subscription))
188: {
189: /* update earliest EID in subscription target */
190: if (state->get_result(state, imc_id, &res) &&
191: res == TNC_IMV_EVALUATION_RESULT_COMPLIANT)
192: {
193: eid = subscription->targets->get_eid(subscription->targets,
194: &eid_epoch);
195: if (eid > 0)
196: {
197: eid = swima_state->get_earliest_eid(swima_state);
198: subscription->targets->set_eid(subscription->targets, eid,
199: eid_epoch);
200: }
201: }
202: DBG1(DBG_IMC, "SWIMA subscription %u:", subscription->request_id);
203: if (!poll_history_log())
204: {
205: return TNC_RESULT_FATAL;
206: }
207: return imc_swima->request_handshake_retry(imc_id, connection_id,
208: TNC_RETRY_REASON_IMC_PERIODIC);
209: }
210: return TNC_RESULT_SUCCESS;
211: case TNC_CONNECTION_STATE_DELETE:
212: return imc_swima->delete_state(imc_swima, connection_id);
213: default:
214: return imc_swima->change_state(imc_swima, connection_id,
215: new_state, NULL);
216: }
217: }
218:
219: /**
220: * Add SWID Inventory or Event attribute to the send queue
221: */
222: static void fulfill_request(imc_state_t *state, imc_msg_t *msg,
223: uint32_t request_id, bool sw_id_only,
224: swima_inventory_t *targets)
225: {
226: pa_tnc_attr_t *attr;
227: swima_collector_t *collector;
228: size_t msg_len = 64;
229: char error_msg[msg_len], *id_str;
230: bool collect_inventory = TRUE;
231: int items;
232:
233: collector = swima_collector_create();
234: id_str = sw_id_only ? " ID" : "";
235:
236: if (targets->get_eid(targets, NULL) > 0)
237: {
238: swima_events_t *sw_ev;
239: ietf_swima_attr_sw_ev_t *sw_ev_attr;
240: imc_swima_state_t *swima_state;
241: uint32_t eid_epoch, last_eid = 0;
242:
243: sw_ev = collector->collect_events(collector, sw_id_only, targets);
244: if (!sw_ev)
245: {
246: snprintf(error_msg, msg_len, "failed to collect SW%s events, "
247: "fallback to SW%s inventory", id_str, id_str);
248: attr = swima_error_create(PA_ERROR_SWIMA, request_id, 0, error_msg);
249: msg->add_attribute(msg, attr);
250: }
251: else {
252: items = sw_ev->get_count(sw_ev);
253: last_eid = sw_ev->get_eid(sw_ev, &eid_epoch, NULL);
254:
255: DBG1(DBG_IMC, "collected %d SW%s event%s at last eid %d of epoch 0x%08x",
256: items, id_str, items == 1 ? "" : "s", last_eid, eid_epoch);
257:
258: /* Store the earliest EID for the next subscription round */
259: swima_state = (imc_swima_state_t*)state;
260: swima_state->set_earliest_eid(swima_state, last_eid + 1);
261:
262: /* Send an IETF SW [Identity] Events attribute */
263: attr = ietf_swima_attr_sw_ev_create(IETF_SWIMA_ATTR_SW_INV_FLAG_NONE,
264: request_id, sw_id_only);
265: sw_ev_attr = (ietf_swima_attr_sw_ev_t*)attr;
266: sw_ev_attr->set_events(sw_ev_attr, sw_ev);
267: collect_inventory = FALSE;
268: }
269: }
270:
271: if (collect_inventory)
272: {
273: swima_inventory_t *sw_inv;
274: ietf_swima_attr_sw_inv_t *sw_inv_attr;
275:
276: sw_inv = collector->collect_inventory(collector, sw_id_only, targets);
277: if (!sw_inv)
278: {
279: snprintf(error_msg, msg_len, "failed to collect SW%s inventory",
280: id_str);
281: attr = swima_error_create(PA_ERROR_SWIMA, request_id, 0, error_msg);
282: }
283: else
284: {
285: items = sw_inv->get_count(sw_inv);
286: DBG1(DBG_IMC, "collected %d SW%s record%s", items, id_str,
287: items == 1 ? "" : "s");
288:
289: /* Send an IETF SW [Identity] Inventory attribute */
290: attr = ietf_swima_attr_sw_inv_create(IETF_SWIMA_ATTR_SW_INV_FLAG_NONE,
291: request_id, sw_id_only);
292: sw_inv_attr = (ietf_swima_attr_sw_inv_t*)attr;
293: sw_inv_attr->set_inventory(sw_inv_attr, sw_inv);
294: }
295: }
296: msg->add_attribute(msg, attr);
297: collector->destroy(collector);
298: }
299:
300: /**
301: * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
302: */
303: TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
304: TNC_ConnectionID connection_id)
305: {
306: imc_state_t *state;
307: imc_swima_state_t *swima_state;
308: imc_msg_t *out_msg;
309: pa_tnc_attr_t *attr;
310: seg_contract_t *contract;
311: seg_contract_manager_t *contracts;
312: imc_swima_subscription_t *subscription;
313: size_t max_attr_size = SWIMA_MAX_ATTR_SIZE;
314: size_t max_seg_size;
315: char buf[BUF_LEN];
316: TNC_Result result = TNC_RESULT_SUCCESS;
317:
318: if (!imc_swima)
319: {
320: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
321: return TNC_RESULT_NOT_INITIALIZED;
322: }
323: if (!imc_swima->get_state(imc_swima, connection_id, &state))
324: {
325: return TNC_RESULT_FATAL;
326: }
327: swima_state = (imc_swima_state_t*)state;
328:
329: if (swima_state->get_subscription(swima_state, &subscription))
330: {
331: if (system(SW_COLLECTOR) != 0)
332: {
333: DBG1(DBG_IMC, "calling %s failed", SW_COLLECTOR);
334: return TNC_RESULT_FATAL;
335: }
336: out_msg = imc_msg_create(imc_swima, state, connection_id, imc_id,
337: subscription->imv_id, msg_types[0]);
338: fulfill_request(state, out_msg, subscription->request_id,
339: subscription->sw_id_only, subscription->targets);
340: }
341: else
342: {
343: /* Determine maximum PA-TNC attribute segment size */
344: max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE
345: - PA_TNC_ATTR_HEADER_SIZE
346: - TCG_SEG_ATTR_SEG_ENV_HEADER;
347:
348: /* Announce support of PA-TNC segmentation to IMV */
349: contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size,
350: TRUE, imc_id, TRUE);
351: contract->get_info_string(contract, buf, BUF_LEN, TRUE);
352: DBG2(DBG_IMC, "%s", buf);
353: contracts = state->get_contracts(state);
354: contracts->add_contract(contracts, contract);
355: attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE);
356:
357: /* send PA-TNC message with the excl flag not set */
358: out_msg = imc_msg_create(imc_swima, state, connection_id, imc_id,
359: TNC_IMVID_ANY, msg_types[0]);
360: out_msg->add_attribute(out_msg, attr);
361: }
362: result = out_msg->send(out_msg, FALSE);
363: out_msg->destroy(out_msg);
364:
365: return result;
366: }
367:
368: static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
369: {
370: imc_msg_t *out_msg;
371: imc_swima_state_t *swima_state;
372: pa_tnc_attr_t *attr;
373: enumerator_t *enumerator;
374: pen_type_t type;
375: TNC_Result result;
376: bool fatal_error = FALSE;
377:
378: /* generate an outgoing PA-TNC message - we might need it */
379: out_msg = imc_msg_create_as_reply(in_msg);
380:
381: /* parse received PA-TNC message and handle local and remote errors */
382: result = in_msg->receive(in_msg, out_msg, &fatal_error);
383: if (result != TNC_RESULT_SUCCESS)
384: {
385: out_msg->destroy(out_msg);
386: return result;
387: }
388:
389: /* analyze PA-TNC attributes */
390: enumerator = in_msg->create_attribute_enumerator(in_msg);
391: while (enumerator->enumerate(enumerator, &attr))
392: {
393: ietf_swima_attr_req_t *attr_req;
394: uint8_t flags;
395: uint32_t request_id;
396: bool sw_id_only;
397: swima_inventory_t *targets;
398: type = attr->get_type(attr);
399:
400: if (type.vendor_id != PEN_IETF || type.type != IETF_ATTR_SWIMA_REQUEST)
401: {
402: continue;
403: }
404:
405: attr_req = (ietf_swima_attr_req_t*)attr;
406: flags = attr_req->get_flags(attr_req);
407: request_id = attr_req->get_request_id(attr_req);
408: targets = attr_req->get_targets(attr_req);
409: sw_id_only = (flags & IETF_SWIMA_ATTR_REQ_FLAG_R);
410:
411: if (flags & (IETF_SWIMA_ATTR_REQ_FLAG_S | IETF_SWIMA_ATTR_REQ_FLAG_C))
412: {
413: if (imc_swima->has_pt_tls(imc_swima) &&
414: lib->settings->get_bool(lib->settings,
415: "%s.plugins.imc-swima.subscriptions", FALSE, lib->ns))
416: {
417: imc_swima_subscription_t *subscription;
418:
419: swima_state = (imc_swima_state_t*)state;
420:
421: if (flags & IETF_SWIMA_ATTR_REQ_FLAG_C)
422: {
423: if (swima_state->get_subscription(swima_state, &subscription))
424: {
425: DBG1(DBG_IMC, "SWIMA subscription %u cleared",
426: subscription->request_id);
427: swima_state->set_subscription(swima_state, NULL, FALSE);
428: }
429: }
430: else
431: {
432: INIT(subscription,
433: .imv_id = in_msg->get_src_id(in_msg),
434: .request_id = request_id,
435: .targets = targets->get_ref(targets),
436: .sw_id_only = sw_id_only,
437: );
438:
439: swima_state->set_subscription(swima_state, subscription,
440: TRUE);
441: DBG1(DBG_IMC, "SWIMA subscription %u established",
442: subscription->request_id);
443: if (system(SW_COLLECTOR) != 0)
444: {
445: DBG1(DBG_IMC, "calling %s failed", SW_COLLECTOR);
446: out_msg->destroy(out_msg);
447: return TNC_RESULT_FATAL;
448: }
449: }
450: }
451: else
452: {
453: attr = swima_error_create(PA_ERROR_SWIMA_SUBSCRIPTION_DENIED,
454: request_id, 0, "subscriptions not enabled");
455: out_msg->add_attribute(out_msg, attr);
456: }
457: }
458:
459: fulfill_request(state, out_msg, request_id, sw_id_only, targets);
460: break;
461: }
462: enumerator->destroy(enumerator);
463:
464: if (fatal_error)
465: {
466: result = TNC_RESULT_FATAL;
467: }
468: else
469: {
470: /* send PA-TNC message with the EXCL flag set */
471: result = out_msg->send(out_msg, TRUE);
472: }
473: out_msg->destroy(out_msg);
474:
475: return result;
476: }
477:
478: /**
479: * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
480:
481: */
482: TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
483: TNC_ConnectionID connection_id,
484: TNC_BufferReference msg,
485: TNC_UInt32 msg_len,
486: TNC_MessageType msg_type)
487: {
488: imc_state_t *state;
489: imc_msg_t *in_msg;
490: TNC_Result result;
491:
492: if (!imc_swima)
493: {
494: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
495: return TNC_RESULT_NOT_INITIALIZED;
496: }
497: if (!imc_swima->get_state(imc_swima, connection_id, &state))
498: {
499: return TNC_RESULT_FATAL;
500: }
501: in_msg = imc_msg_create_from_data(imc_swima, state, connection_id, msg_type,
502: chunk_create(msg, msg_len));
503: result = receive_message(state, in_msg);
504: in_msg->destroy(in_msg);
505:
506: return result;
507: }
508:
509: /**
510: * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
511: */
512: TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
513: TNC_ConnectionID connection_id,
514: TNC_UInt32 msg_flags,
515: TNC_BufferReference msg,
516: TNC_UInt32 msg_len,
517: TNC_VendorID msg_vid,
518: TNC_MessageSubtype msg_subtype,
519: TNC_UInt32 src_imv_id,
520: TNC_UInt32 dst_imc_id)
521: {
522: imc_state_t *state;
523: imc_msg_t *in_msg;
524: TNC_Result result;
525:
526: if (!imc_swima)
527: {
528: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
529: return TNC_RESULT_NOT_INITIALIZED;
530: }
531: if (!imc_swima->get_state(imc_swima, connection_id, &state))
532: {
533: return TNC_RESULT_FATAL;
534: }
535: in_msg = imc_msg_create_from_long_data(imc_swima, state, connection_id,
536: src_imv_id, dst_imc_id,msg_vid, msg_subtype,
537: chunk_create(msg, msg_len));
538: result =receive_message(state, in_msg);
539: in_msg->destroy(in_msg);
540:
541: return result;
542: }
543:
544: /**
545: * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
546: */
547: TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
548: TNC_ConnectionID connection_id)
549: {
550: if (!imc_swima)
551: {
552: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
553: return TNC_RESULT_NOT_INITIALIZED;
554: }
555: return TNC_RESULT_SUCCESS;
556: }
557:
558: /**
559: * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
560: */
561: TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
562: {
563: if (!imc_swima)
564: {
565: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
566: return TNC_RESULT_NOT_INITIALIZED;
567: }
568: imc_swima->destroy(imc_swima);
569: imc_swima = NULL;
570:
571: return TNC_RESULT_SUCCESS;
572: }
573:
574: /**
575: * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
576: */
577: TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
578: TNC_TNCC_BindFunctionPointer bind_function)
579: {
580: if (!imc_swima)
581: {
582: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
583: return TNC_RESULT_NOT_INITIALIZED;
584: }
585: return imc_swima->bind_functions(imc_swima, bind_function);
586: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>