]>
Commit | Line | Data |
---|---|---|
1ecff259 | 1 | /* |
00cd79b6 | 2 | * Copyright (C) 2013-2015 Andreas Steffen |
1ecff259 AS |
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" | |
b18a5317 | 18 | |
1ecff259 AS |
19 | #include <library.h> |
20 | #include <utils/debug.h> | |
21 | ||
00cd79b6 AS |
22 | #include <tncif_names.h> |
23 | ||
1ecff259 AS |
24 | #include <stdlib.h> |
25 | #include <stdio.h> | |
632e5b0b | 26 | #include <time.h> |
1ecff259 | 27 | |
59c9ec10 AS |
28 | /* The default policy group #1 is assumed to always exist */ |
29 | #define DEFAULT_GROUP_ID 1 | |
30 | ||
1ecff259 AS |
31 | /** |
32 | * global debug output variables | |
33 | */ | |
b1da8368 | 34 | static int debug_level = 1; |
1ecff259 AS |
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 | ||
f4dcbe3b AS |
56 | /** |
57 | * Collect all enforcements by iterating up through parent groups | |
58 | */ | |
ea6ab9fb AS |
59 | static bool iterate_enforcements(database_t *db, int device_id, int session_id, |
60 | int group_id) | |
1ecff259 | 61 | { |
ea6ab9fb AS |
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; | |
65148217 | 65 | char *argument; |
ea6ab9fb AS |
66 | time_t now; |
67 | enumerator_t *e, *e1, *e2; | |
68 | ||
69 | now = time(NULL); | |
65148217 | 70 | |
a45a2c92 | 71 | while (group_id) |
65148217 | 72 | { |
ea6ab9fb AS |
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 " | |
a45a2c92 AS |
76 | "FROM enforcements AS e JOIN policies as p ON e.policy = p.id " |
77 | "WHERE e.group_id = ?", DB_INT, group_id, | |
ea6ab9fb AS |
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) | |
b1da8368 | 81 | { |
a45a2c92 | 82 | return FALSE; |
b1da8368 | 83 | } |
ea6ab9fb AS |
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)) | |
a45a2c92 | 87 | { |
ea6ab9fb AS |
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 | ||
a45a2c92 AS |
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 | } | |
b1da8368 | 136 | |
a45a2c92 AS |
137 | /* insert a workitem */ |
138 | if (db->execute(db, NULL, | |
b1da8368 AS |
139 | "INSERT INTO workitems (session, enforcement, type, arg_str, " |
140 | "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)", | |
65148217 | 141 | DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument, |
ea6ab9fb AS |
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) | |
a45a2c92 | 144 | { |
ea6ab9fb | 145 | e1->destroy(e1); |
a45a2c92 AS |
146 | fprintf(stderr, "could not insert workitem\n"); |
147 | return FALSE; | |
148 | } | |
149 | } | |
ea6ab9fb | 150 | e1->destroy(e1); |
a45a2c92 AS |
151 | |
152 | e = db->query(db, | |
153 | "SELECT parent FROM groups WHERE id = ?", | |
154 | DB_INT, group_id, DB_INT); | |
155 | if (!e) | |
65148217 | 156 | { |
65148217 AS |
157 | return FALSE; |
158 | } | |
a45a2c92 AS |
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); | |
65148217 | 169 | } |
1ecff259 AS |
170 | return TRUE; |
171 | } | |
172 | ||
f4dcbe3b AS |
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 */ | |
a21d4096 | 193 | if (device_id && created) |
f4dcbe3b AS |
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 | { | |
ea6ab9fb | 204 | if (!iterate_enforcements(db, device_id, session_id, group_id)) |
f4dcbe3b AS |
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 | ||
ea6ab9fb | 250 | return iterate_enforcements(db, device_id, session_id, group_id); |
f4dcbe3b AS |
251 | } |
252 | ||
253 | static bool policy_stop(database_t *db, int session_id) | |
1ecff259 | 254 | { |
65148217 | 255 | enumerator_t *e; |
00cd79b6 AS |
256 | int rec, policy, final_rec, id_type; |
257 | chunk_t id_value; | |
79b5a33c AS |
258 | char *result, *format, *ip_address = NULL; |
259 | char command[512]; | |
00cd79b6 | 260 | bool success = TRUE; |
65148217 | 261 | |
00cd79b6 | 262 | /* store all workitem results for this session in the results table */ |
65148217 AS |
263 | e = db->query(db, |
264 | "SELECT w.rec_final, w.result, e.policy FROM workitems AS w " | |
e1db511b AS |
265 | "JOIN enforcements AS e ON w.enforcement = e.id " |
266 | "WHERE w.session = ? AND w.result IS NOT NULL", | |
65148217 AS |
267 | DB_INT, session_id, DB_INT, DB_TEXT, DB_INT); |
268 | if (e) | |
269 | { | |
270 | while (e->enumerate(e, &rec, &result, &policy)) | |
271 | { | |
65148217 AS |
272 | db->execute(db, NULL, |
273 | "INSERT INTO results (session, policy, rec, result) " | |
274 | "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy, | |
275 | DB_INT, rec, DB_TEXT, result); | |
276 | } | |
277 | e->destroy(e); | |
65148217 | 278 | } |
00cd79b6 AS |
279 | else |
280 | { | |
281 | success = FALSE; | |
282 | } | |
283 | ||
284 | /* delete all workitems for this session from the database */ | |
285 | if (db->execute(db, NULL, | |
286 | "DELETE FROM workitems WHERE session = ?", | |
287 | DB_UINT, session_id) < 0) | |
288 | { | |
289 | success = FALSE; | |
290 | } | |
291 | ||
292 | final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; | |
293 | ||
294 | /* retrieve the final recommendation for this session */ | |
295 | e = db->query(db, | |
296 | "SELECT rec FROM sessions WHERE id = ?", | |
297 | DB_INT, session_id, DB_INT); | |
298 | if (e) | |
299 | { | |
300 | if (!e->enumerate(e, &final_rec)) | |
301 | { | |
302 | success = FALSE; | |
303 | } | |
304 | e->destroy(e); | |
305 | } | |
306 | else | |
307 | { | |
308 | success = FALSE; | |
309 | } | |
310 | ||
311 | /* retrieve client IP address for this session */ | |
312 | e = db->query(db, | |
313 | "SELECT i.type, i.value FROM identities AS i " | |
314 | "JOIN sessions_identities AS si ON si.identity_id = i.id " | |
315 | "WHERE si.session_id = ? AND (i.type = ? OR i.type = ?)", | |
316 | DB_INT, session_id, DB_INT, TNC_ID_IPV4_ADDR, DB_INT, | |
317 | TNC_ID_IPV6_ADDR, DB_INT, DB_BLOB); | |
318 | if (e) | |
319 | { | |
320 | if (e->enumerate(e, &id_type, &id_value)) | |
321 | { | |
322 | ip_address = strndup(id_value.ptr, id_value.len); | |
323 | } | |
324 | else | |
325 | { | |
326 | success = FALSE; | |
327 | } | |
328 | e->destroy(e); | |
329 | } | |
330 | else | |
331 | { | |
332 | success = FALSE; | |
333 | } | |
334 | ||
335 | fprintf(stderr, "recommendation for access requestor %s is %N\n", | |
336 | ip_address ? ip_address : "0.0.0.0", | |
337 | TNC_IMV_Action_Recommendation_names, final_rec); | |
79b5a33c AS |
338 | |
339 | if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW) | |
340 | { | |
341 | format = lib->settings->get_str(lib->settings, | |
342 | "imv_policy_manager.command_allow", NULL); | |
343 | } | |
344 | else | |
345 | { | |
346 | format = lib->settings->get_str(lib->settings, | |
347 | "imv_policy_manager.command_block", NULL); | |
348 | } | |
349 | if (format && ip_address) | |
350 | { | |
351 | /* the IP address can occur at most twice in the command string */ | |
352 | snprintf(command, sizeof(command), format, ip_address, ip_address); | |
353 | success = system(command) == 0; | |
354 | fprintf(stderr, "%s system command: %s\n", | |
355 | success ? "successful" : "failed", command); | |
356 | } | |
00cd79b6 AS |
357 | free(ip_address); |
358 | ||
359 | return success; | |
1ecff259 AS |
360 | } |
361 | ||
362 | int main(int argc, char *argv[]) | |
363 | { | |
364 | database_t *db; | |
ecc6c2e8 | 365 | char *uri; |
1ecff259 AS |
366 | int session_id; |
367 | bool start, success; | |
368 | ||
369 | /* enable attest debugging hook */ | |
370 | dbg = stderr_dbg; | |
371 | ||
372 | atexit(library_deinit); | |
373 | ||
374 | /* initialize library */ | |
34d3bfcf | 375 | if (!library_init(NULL, "imv_policy_manager")) |
1ecff259 AS |
376 | { |
377 | exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); | |
378 | } | |
b18a5317 | 379 | if (!lib->plugins->load(lib->plugins, |
1ecff259 AS |
380 | lib->settings->get_str(lib->settings, "imv_policy_manager.load", |
381 | "sqlite"))) | |
382 | { | |
383 | exit(SS_RC_INITIALIZATION_FAILED); | |
384 | } | |
385 | ||
ecc6c2e8 | 386 | if (argc < 3) |
1ecff259 AS |
387 | { |
388 | usage(); | |
389 | exit(SS_RC_INITIALIZATION_FAILED); | |
390 | } | |
391 | if (streq(argv[1], "start")) | |
392 | { | |
393 | start = TRUE; | |
394 | } | |
395 | else if (streq(argv[1], "stop")) | |
396 | { | |
397 | start = FALSE; | |
398 | } | |
399 | else | |
400 | { | |
401 | usage(); | |
402 | exit(SS_RC_INITIALIZATION_FAILED); | |
403 | } | |
404 | ||
ecc6c2e8 | 405 | session_id = atoi(argv[2]); |
b18a5317 | 406 | |
4f6bf1a8 | 407 | /* attach IMV database */ |
1ec34763 TB |
408 | uri = lib->settings->get_str(lib->settings, |
409 | "imv_policy_manager.database", | |
410 | lib->settings->get_str(lib->settings, | |
411 | "charon.imcv.database", | |
412 | lib->settings->get_str(lib->settings, | |
413 | "libimcv.database", NULL))); | |
b1da8368 AS |
414 | if (!uri) |
415 | { | |
416 | fprintf(stderr, "database uri not defined.\n"); | |
417 | exit(SS_RC_INITIALIZATION_FAILED); | |
418 | } | |
419 | ||
1ecff259 AS |
420 | db = lib->db->create(lib->db, uri); |
421 | if (!db) | |
422 | { | |
423 | fprintf(stderr, "opening database failed.\n"); | |
424 | exit(SS_RC_INITIALIZATION_FAILED); | |
425 | } | |
426 | ||
427 | if (start) | |
428 | { | |
429 | success = policy_start(db, session_id); | |
430 | } | |
431 | else | |
432 | { | |
433 | success = policy_stop(db, session_id); | |
434 | } | |
435 | db->destroy(db); | |
436 | ||
437 | fprintf(stderr, "imv_policy_manager %s %s\n", start ? "start" : "stop", | |
438 | success ? "successful" : "failed"); | |
439 | ||
440 | exit(EXIT_SUCCESS); | |
441 | } |