]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libimcv/imv/imv_policy_manager.c
9f7e4e8f49e2d7b6e6ae1f7a6357ed78afbe942b
[thirdparty/strongswan.git] / src / libimcv / imv / imv_policy_manager.c
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 enforcment %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 default:
134 arg_int = 0;
135 }
136
137 /* insert a workitem */
138 if (db->execute(db, NULL,
139 "INSERT INTO workitems (session, enforcement, type, arg_str, "
140 "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)",
141 DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument,
142 DB_INT, arg_int, DB_INT, e_rec_fail ? e_rec_fail : p_rec_fail,
143 DB_INT, e_rec_noresult ? e_rec_noresult : p_rec_noresult) != 1)
144 {
145 e1->destroy(e1);
146 fprintf(stderr, "could not insert workitem\n");
147 return FALSE;
148 }
149 }
150 e1->destroy(e1);
151
152 e = db->query(db,
153 "SELECT parent FROM groups WHERE id = ?",
154 DB_INT, group_id, DB_INT);
155 if (!e)
156 {
157 return FALSE;
158 }
159 if (e->enumerate(e, &parent))
160 {
161 group_id = parent;
162 }
163 else
164 {
165 fprintf(stderr, "group information not found\n");
166 group_id = 0;
167 }
168 e->destroy(e);
169 }
170 return TRUE;
171 }
172
173 static bool policy_start(database_t *db, int session_id)
174 {
175 enumerator_t *e;
176 int device_id, product_id, gid, group_id = DEFAULT_GROUP_ID;
177 u_int created;
178
179 /* get session data */
180 e = db->query(db,
181 "SELECT s.device, s.product, d.created FROM sessions AS s "
182 "LEFT JOIN devices AS d ON s.device = d.id WHERE s.id = ?",
183 DB_INT, session_id, DB_INT, DB_INT, DB_UINT);
184 if (!e || !e->enumerate(e, &device_id, &product_id, &created))
185 {
186 DESTROY_IF(e);
187 fprintf(stderr, "session %d not found\n", session_id);
188 return FALSE;
189 }
190 e->destroy(e);
191
192 /* if a device ID with a creation date exists, get all group memberships */
193 if (device_id && created)
194 {
195 e = db->query(db,
196 "SELECT group_id FROM groups_members WHERE device_id = ?",
197 DB_INT, device_id, DB_INT);
198 if (!e)
199 {
200 return FALSE;
201 }
202 while (e->enumerate(e, &group_id))
203 {
204 if (!iterate_enforcements(db, device_id, session_id, group_id))
205 {
206 e->destroy(e);
207 return FALSE;
208 }
209 }
210 e->destroy(e);
211
212 return TRUE;
213 }
214
215 /* determine if a default product group exists */
216 e = db->query(db,
217 "SELECT group_id FROM groups_product_defaults "
218 "WHERE product_id = ?", DB_INT, product_id, DB_INT);
219 if (!e)
220 {
221 return FALSE;
222 }
223 if (e->enumerate(e, &gid))
224 {
225 group_id = gid;
226 }
227 e->destroy(e);
228
229 if (device_id && !created)
230 {
231 /* assign a newly created device to a default group */
232 if (db->execute(db, NULL,
233 "INSERT INTO groups_members (device_id, group_id) "
234 "VALUES (?, ?)", DB_INT, device_id, DB_INT, group_id) != 1)
235 {
236 fprintf(stderr, "could not assign device to a default group\n");
237 return FALSE;
238 }
239
240 /* set the creation date if it hasn't been set yet */
241 if (db->execute(db, NULL,
242 "UPDATE devices SET created = ? WHERE id = ?",
243 DB_UINT, time(NULL), DB_INT, device_id) != 1)
244 {
245 fprintf(stderr, "creation date of device could not be set\n");
246 return FALSE;
247 }
248 }
249
250 return iterate_enforcements(db, device_id, session_id, group_id);
251 }
252
253 static bool policy_stop(database_t *db, int session_id)
254 {
255 enumerator_t *e;
256 int rec, policy, final_rec, id_type;
257 chunk_t id_value;
258 char *result, *ip_address = NULL;
259 bool success = TRUE;
260
261 /* store all workitem results for this session in the results table */
262 e = db->query(db,
263 "SELECT w.rec_final, w.result, e.policy FROM workitems AS w "
264 "JOIN enforcements AS e ON w.enforcement = e.id "
265 "WHERE w.session = ? AND w.result IS NOT NULL",
266 DB_INT, session_id, DB_INT, DB_TEXT, DB_INT);
267 if (e)
268 {
269 while (e->enumerate(e, &rec, &result, &policy))
270 {
271 db->execute(db, NULL,
272 "INSERT INTO results (session, policy, rec, result) "
273 "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy,
274 DB_INT, rec, DB_TEXT, result);
275 }
276 e->destroy(e);
277 }
278 else
279 {
280 success = FALSE;
281 }
282
283 /* delete all workitems for this session from the database */
284 if (db->execute(db, NULL,
285 "DELETE FROM workitems WHERE session = ?",
286 DB_UINT, session_id) < 0)
287 {
288 success = FALSE;
289 }
290
291 final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
292
293 /* retrieve the final recommendation for this session */
294 e = db->query(db,
295 "SELECT rec FROM sessions WHERE id = ?",
296 DB_INT, session_id, DB_INT);
297 if (e)
298 {
299 if (!e->enumerate(e, &final_rec))
300 {
301 success = FALSE;
302 }
303 e->destroy(e);
304 }
305 else
306 {
307 success = FALSE;
308 }
309
310 /* retrieve client IP address for this session */
311 e = db->query(db,
312 "SELECT i.type, i.value FROM identities AS i "
313 "JOIN sessions_identities AS si ON si.identity_id = i.id "
314 "WHERE si.session_id = ? AND (i.type = ? OR i.type = ?)",
315 DB_INT, session_id, DB_INT, TNC_ID_IPV4_ADDR, DB_INT,
316 TNC_ID_IPV6_ADDR, DB_INT, DB_BLOB);
317 if (e)
318 {
319 if (e->enumerate(e, &id_type, &id_value))
320 {
321 ip_address = strndup(id_value.ptr, id_value.len);
322 }
323 else
324 {
325 success = FALSE;
326 }
327 e->destroy(e);
328 }
329 else
330 {
331 success = FALSE;
332 }
333
334 fprintf(stderr, "recommendation for access requestor %s is %N\n",
335 ip_address ? ip_address : "0.0.0.0",
336 TNC_IMV_Action_Recommendation_names, final_rec);
337 free(ip_address);
338
339 return success;
340 }
341
342 int main(int argc, char *argv[])
343 {
344 database_t *db;
345 char *uri;
346 int session_id;
347 bool start, success;
348
349 /* enable attest debugging hook */
350 dbg = stderr_dbg;
351
352 atexit(library_deinit);
353
354 /* initialize library */
355 if (!library_init(NULL, "imv_policy_manager"))
356 {
357 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
358 }
359 if (!lib->plugins->load(lib->plugins,
360 lib->settings->get_str(lib->settings, "imv_policy_manager.load",
361 "sqlite")))
362 {
363 exit(SS_RC_INITIALIZATION_FAILED);
364 }
365
366 if (argc < 3)
367 {
368 usage();
369 exit(SS_RC_INITIALIZATION_FAILED);
370 }
371 if (streq(argv[1], "start"))
372 {
373 start = TRUE;
374 }
375 else if (streq(argv[1], "stop"))
376 {
377 start = FALSE;
378 }
379 else
380 {
381 usage();
382 exit(SS_RC_INITIALIZATION_FAILED);
383 }
384
385 session_id = atoi(argv[2]);
386
387 /* attach IMV database */
388 uri = lib->settings->get_str(lib->settings,
389 "imv_policy_manager.database",
390 lib->settings->get_str(lib->settings,
391 "charon.imcv.database",
392 lib->settings->get_str(lib->settings,
393 "libimcv.database", NULL)));
394 if (!uri)
395 {
396 fprintf(stderr, "database uri not defined.\n");
397 exit(SS_RC_INITIALIZATION_FAILED);
398 }
399
400 db = lib->db->create(lib->db, uri);
401 if (!db)
402 {
403 fprintf(stderr, "opening database failed.\n");
404 exit(SS_RC_INITIALIZATION_FAILED);
405 }
406
407 if (start)
408 {
409 success = policy_start(db, session_id);
410 }
411 else
412 {
413 success = policy_stop(db, session_id);
414 }
415 db->destroy(db);
416
417 fprintf(stderr, "imv_policy_manager %s %s\n", start ? "start" : "stop",
418 success ? "successful" : "failed");
419
420 exit(EXIT_SUCCESS);
421 }