Annotation of embedaddon/strongswan/src/libimcv/imv/imv_policy_manager.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013-2015 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 "imv_policy_manager_usage.h"
17: #include "imv_workitem.h"
18:
19: #include <library.h>
20: #include <utils/debug.h>
21:
22: #include <tncif_names.h>
23:
24: #include <stdlib.h>
25: #include <stdio.h>
26: #include <time.h>
27:
28: /* The default policy group #1 is assumed to always exist */
29: #define DEFAULT_GROUP_ID 1
30:
31: /**
32: * global debug output variables
33: */
34: static int debug_level = 1;
35: static bool stderr_quiet = FALSE;
36:
37: /**
38: * attest dbg function
39: */
40: static void stderr_dbg(debug_t group, level_t level, char *fmt, ...)
41: {
42: va_list args;
43:
44: if (level <= debug_level)
45: {
46: if (!stderr_quiet)
47: {
48: va_start(args, fmt);
49: vfprintf(stderr, fmt, args);
50: fprintf(stderr, "\n");
51: va_end(args);
52: }
53: }
54: }
55:
56: /**
57: * Collect all enforcements by iterating up through parent groups
58: */
59: static bool iterate_enforcements(database_t *db, int device_id, int session_id,
60: int group_id)
61: {
62: int id, type, file, dir, arg_int, parent, policy, max_age;
63: int p_rec_fail, p_rec_noresult, e_rec_fail, e_rec_noresult, latest_rec;
64: bool latest_success;
65: char *argument;
66: time_t now;
67: enumerator_t *e, *e1, *e2;
68:
69: now = time(NULL);
70:
71: while (group_id)
72: {
73: e1 = db->query(db,
74: "SELECT e.id, p.type, p.argument, p.file, p.dir, p.rec_fail, "
75: "p.rec_noresult, e.policy, e.max_age, e.rec_fail, e.rec_noresult "
76: "FROM enforcements AS e JOIN policies as p ON e.policy = p.id "
77: "WHERE e.group_id = ?", DB_INT, group_id,
78: DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_INT,
79: DB_INT, DB_INT, DB_INT, DB_INT);
80: if (!e1)
81: {
82: return FALSE;
83: }
84: while (e1->enumerate(e1, &id, &type, &argument, &file, &dir,
85: &p_rec_fail, &p_rec_noresult, &policy, &max_age,
86: &e_rec_fail, &e_rec_noresult))
87: {
88: /* check if the latest measurement of the device was successful */
89: latest_success = FALSE;
90:
91: if (device_id)
92: {
93: e2 = db->query(db,
94: "SELECT r.rec FROM results AS r "
95: "JOIN sessions AS s ON s.id = r.session "
96: "WHERE r.policy = ? AND s.device = ? AND s.time > ? "
97: "ORDER BY s.time DESC",
98: DB_INT, policy, DB_INT, device_id,
99: DB_UINT, now - max_age, DB_INT);
100: if (!e2)
101: {
102: e1->destroy(e1);
103: return FALSE;
104: }
105: if (e2->enumerate(e2, &latest_rec) &&
106: latest_rec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
107: {
108: latest_success = TRUE;
109: }
110: e2->destroy(e2);
111: }
112:
113: if (latest_success)
114: {
115: /*skipping enforcement */
116: printf("skipping enforcement %d\n", id);
117: continue;
118: }
119:
120: /* determine arg_int */
121: switch ((imv_workitem_type_t)type)
122: {
123: case IMV_WORKITEM_FILE_REF_MEAS:
124: case IMV_WORKITEM_FILE_MEAS:
125: case IMV_WORKITEM_FILE_META:
126: arg_int = file;
127: break;
128: case IMV_WORKITEM_DIR_REF_MEAS:
129: case IMV_WORKITEM_DIR_MEAS:
130: case IMV_WORKITEM_DIR_META:
131: arg_int = dir;
132: break;
133: case IMV_WORKITEM_SWID_TAGS:
134: /* software [identifier] inventory by default */
135: arg_int = 0;
136:
137: /* software identifiers only? */
138: if (device_id && strchr(argument, 'R'))
139: {
140: /* get last EID in order to set earliest EID */
141: e2 = db->query(db,
142: "SELECT eid FROM swid_events where device == ? "
143: "ORDER BY eid DESC", DB_UINT, device_id, DB_INT);
144: if (e2)
145: {
146: if (e2->enumerate(e2, &arg_int))
147: {
148: arg_int++;
149: }
150: else
151: {
152: arg_int = 1;
153: }
154: e2->destroy(e2);
155: }
156: }
157: break;
158: default:
159: arg_int = 0;
160: }
161:
162: /* insert a workitem */
163: if (db->execute(db, NULL,
164: "INSERT INTO workitems (session, enforcement, type, arg_str, "
165: "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)",
166: DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument,
167: DB_INT, arg_int, DB_INT, e_rec_fail ? e_rec_fail : p_rec_fail,
168: DB_INT, e_rec_noresult ? e_rec_noresult : p_rec_noresult) != 1)
169: {
170: e1->destroy(e1);
171: fprintf(stderr, "could not insert workitem\n");
172: return FALSE;
173: }
174: }
175: e1->destroy(e1);
176:
177: e = db->query(db,
178: "SELECT parent FROM groups WHERE id = ?",
179: DB_INT, group_id, DB_INT);
180: if (!e)
181: {
182: return FALSE;
183: }
184: if (e->enumerate(e, &parent))
185: {
186: group_id = parent;
187: }
188: else
189: {
190: fprintf(stderr, "group information not found\n");
191: group_id = 0;
192: }
193: e->destroy(e);
194: }
195: return TRUE;
196: }
197:
198: static bool policy_start(database_t *db, int session_id)
199: {
200: enumerator_t *e;
201: int device_id, product_id, gid, group_id = DEFAULT_GROUP_ID;
202: u_int created;
203:
204: /* get session data */
205: e = db->query(db,
206: "SELECT s.device, s.product, d.created FROM sessions AS s "
207: "LEFT JOIN devices AS d ON s.device = d.id WHERE s.id = ?",
208: DB_INT, session_id, DB_INT, DB_INT, DB_UINT);
209: if (!e || !e->enumerate(e, &device_id, &product_id, &created))
210: {
211: DESTROY_IF(e);
212: fprintf(stderr, "session %d not found\n", session_id);
213: return FALSE;
214: }
215: e->destroy(e);
216:
217: /* if a device ID with a creation date exists, get all group memberships */
218: if (device_id && created)
219: {
220: e = db->query(db,
221: "SELECT group_id FROM groups_members WHERE device_id = ?",
222: DB_INT, device_id, DB_INT);
223: if (!e)
224: {
225: return FALSE;
226: }
227: while (e->enumerate(e, &group_id))
228: {
229: if (!iterate_enforcements(db, device_id, session_id, group_id))
230: {
231: e->destroy(e);
232: return FALSE;
233: }
234: }
235: e->destroy(e);
236:
237: return TRUE;
238: }
239:
240: /* determine if a default product group exists */
241: e = db->query(db,
242: "SELECT group_id FROM groups_product_defaults "
243: "WHERE product_id = ?", DB_INT, product_id, DB_INT);
244: if (!e)
245: {
246: return FALSE;
247: }
248: if (e->enumerate(e, &gid))
249: {
250: group_id = gid;
251: }
252: e->destroy(e);
253:
254: if (device_id && !created)
255: {
256: /* assign a newly created device to a default group */
257: if (db->execute(db, NULL,
258: "INSERT INTO groups_members (device_id, group_id) "
259: "VALUES (?, ?)", DB_INT, device_id, DB_INT, group_id) != 1)
260: {
261: fprintf(stderr, "could not assign device to a default group\n");
262: return FALSE;
263: }
264:
265: /* set the creation date if it hasn't been set yet */
266: if (db->execute(db, NULL,
267: "UPDATE devices SET created = ? WHERE id = ?",
268: DB_UINT, time(NULL), DB_INT, device_id) != 1)
269: {
270: fprintf(stderr, "creation date of device could not be set\n");
271: return FALSE;
272: }
273: }
274:
275: return iterate_enforcements(db, device_id, session_id, group_id);
276: }
277:
278: static bool policy_stop(database_t *db, int session_id)
279: {
280: enumerator_t *e;
281: int rec, policy, final_rec, id_type;
282: chunk_t id_value;
283: char *result, *format, *ip_address = NULL;
284: char command[512];
285: bool success = TRUE;
286:
287: /* store all workitem results for this session in the results table */
288: e = db->query(db,
289: "SELECT w.rec_final, w.result, e.policy FROM workitems AS w "
290: "JOIN enforcements AS e ON w.enforcement = e.id "
291: "WHERE w.session = ? AND w.result IS NOT NULL",
292: DB_INT, session_id, DB_INT, DB_TEXT, DB_INT);
293: if (e)
294: {
295: while (e->enumerate(e, &rec, &result, &policy))
296: {
297: db->execute(db, NULL,
298: "INSERT INTO results (session, policy, rec, result) "
299: "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy,
300: DB_INT, rec, DB_TEXT, result);
301: }
302: e->destroy(e);
303: }
304: else
305: {
306: success = FALSE;
307: }
308:
309: /* delete all workitems for this session from the database */
310: if (db->execute(db, NULL,
311: "DELETE FROM workitems WHERE session = ?",
312: DB_UINT, session_id) < 0)
313: {
314: success = FALSE;
315: }
316:
317: final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
318:
319: /* retrieve the final recommendation for this session */
320: e = db->query(db,
321: "SELECT rec FROM sessions WHERE id = ?",
322: DB_INT, session_id, DB_INT);
323: if (e)
324: {
325: if (!e->enumerate(e, &final_rec))
326: {
327: success = FALSE;
328: }
329: e->destroy(e);
330: }
331: else
332: {
333: success = FALSE;
334: }
335:
336: /* retrieve client IP address for this session */
337: e = db->query(db,
338: "SELECT i.type, i.value FROM identities AS i "
339: "JOIN sessions_identities AS si ON si.identity_id = i.id "
340: "WHERE si.session_id = ? AND (i.type = ? OR i.type = ?)",
341: DB_INT, session_id, DB_INT, TNC_ID_IPV4_ADDR, DB_INT,
342: TNC_ID_IPV6_ADDR, DB_INT, DB_BLOB);
343: if (e)
344: {
345: if (e->enumerate(e, &id_type, &id_value))
346: {
347: ip_address = strndup(id_value.ptr, id_value.len);
348: }
349: else
350: {
351: success = FALSE;
352: }
353: e->destroy(e);
354: }
355: else
356: {
357: success = FALSE;
358: }
359:
360: fprintf(stderr, "recommendation for access requestor %s is %N\n",
361: ip_address ? ip_address : "0.0.0.0",
362: TNC_IMV_Action_Recommendation_names, final_rec);
363:
364: if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
365: {
366: format = lib->settings->get_str(lib->settings,
367: "imv_policy_manager.command_allow", NULL);
368: }
369: else
370: {
371: format = lib->settings->get_str(lib->settings,
372: "imv_policy_manager.command_block", NULL);
373: }
374: if (format && ip_address)
375: {
376: /* the IP address can occur at most twice in the command string */
377: snprintf(command, sizeof(command), format, ip_address, ip_address);
378: success = system(command) == 0;
379: fprintf(stderr, "%s system command: %s\n",
380: success ? "successful" : "failed", command);
381: }
382: free(ip_address);
383:
384: return success;
385: }
386:
387: int main(int argc, char *argv[])
388: {
389: database_t *db;
390: char *uri;
391: int session_id;
392: bool start, success;
393:
394: /* enable attest debugging hook */
395: dbg = stderr_dbg;
396:
397: atexit(library_deinit);
398:
399: /* initialize library */
400: if (!library_init(NULL, "imv_policy_manager"))
401: {
402: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
403: }
404: if (!lib->plugins->load(lib->plugins,
405: lib->settings->get_str(lib->settings, "imv_policy_manager.load",
406: "sqlite")))
407: {
408: exit(SS_RC_INITIALIZATION_FAILED);
409: }
410:
411: if (argc < 3)
412: {
413: usage();
414: exit(SS_RC_INITIALIZATION_FAILED);
415: }
416: if (streq(argv[1], "start"))
417: {
418: start = TRUE;
419: }
420: else if (streq(argv[1], "stop"))
421: {
422: start = FALSE;
423: }
424: else
425: {
426: usage();
427: exit(SS_RC_INITIALIZATION_FAILED);
428: }
429:
430: session_id = atoi(argv[2]);
431:
432: /* attach IMV database */
433: uri = lib->settings->get_str(lib->settings,
434: "imv_policy_manager.database",
435: lib->settings->get_str(lib->settings,
436: "charon.imcv.database",
437: lib->settings->get_str(lib->settings,
438: "libimcv.database", NULL)));
439: if (!uri)
440: {
441: fprintf(stderr, "database uri not defined.\n");
442: exit(SS_RC_INITIALIZATION_FAILED);
443: }
444:
445: db = lib->db->create(lib->db, uri);
446: if (!db)
447: {
448: fprintf(stderr, "opening database failed.\n");
449: exit(SS_RC_INITIALIZATION_FAILED);
450: }
451:
452: if (start)
453: {
454: success = policy_start(db, session_id);
455: }
456: else
457: {
458: success = policy_stop(db, session_id);
459: }
460: db->destroy(db);
461:
462: fprintf(stderr, "imv_policy_manager %s %s\n", start ? "start" : "stop",
463: success ? "successful" : "failed");
464:
465: exit(EXIT_SUCCESS);
466: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>