2 * Copyright (C) 2013-2015 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "imv_policy_manager_usage.h"
17 #include "imv_workitem.h"
20 #include <utils/debug.h>
22 #include <tncif_names.h>
28 /* The default policy group #1 is assumed to always exist */
29 #define DEFAULT_GROUP_ID 1
32 * global debug output variables
34 static int debug_level
= 1;
35 static bool stderr_quiet
= FALSE
;
40 static void stderr_dbg(debug_t group
, level_t level
, char *fmt
, ...)
44 if (level
<= debug_level
)
49 vfprintf(stderr
, fmt
, args
);
50 fprintf(stderr
, "\n");
57 * Collect all enforcements by iterating up through parent groups
59 static bool iterate_enforcements(database_t
*db
, int device_id
, int session_id
,
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
;
67 enumerator_t
*e
, *e1
, *e2
;
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
);
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
))
88 /* check if the latest measurement of the device was successful */
89 latest_success
= FALSE
;
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
);
105 if (e2
->enumerate(e2
, &latest_rec
) &&
106 latest_rec
== TNC_IMV_ACTION_RECOMMENDATION_ALLOW
)
108 latest_success
= TRUE
;
115 /*skipping enforcement */
116 printf("skipping enforcement %d\n", id
);
120 /* determine arg_int */
121 switch ((imv_workitem_type_t
)type
)
123 case IMV_WORKITEM_FILE_REF_MEAS
:
124 case IMV_WORKITEM_FILE_MEAS
:
125 case IMV_WORKITEM_FILE_META
:
128 case IMV_WORKITEM_DIR_REF_MEAS
:
129 case IMV_WORKITEM_DIR_MEAS
:
130 case IMV_WORKITEM_DIR_META
:
133 case IMV_WORKITEM_SWID_TAGS
:
134 /* software [identifier] inventory by default */
137 /* software identifiers only? */
138 if (device_id
&& strchr(argument
, 'R'))
140 /* get last EID in order to set earliest EID */
142 "SELECT eid FROM swid_events where device == ? "
143 "ORDER BY eid DESC", DB_UINT
, device_id
, DB_INT
);
146 if (e2
->enumerate(e2
, &arg_int
))
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)
171 fprintf(stderr
, "could not insert workitem\n");
178 "SELECT parent FROM groups WHERE id = ?",
179 DB_INT
, group_id
, DB_INT
);
184 if (e
->enumerate(e
, &parent
))
190 fprintf(stderr
, "group information not found\n");
198 static bool policy_start(database_t
*db
, int session_id
)
201 int device_id
, product_id
, gid
, group_id
= DEFAULT_GROUP_ID
;
204 /* get session data */
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
))
212 fprintf(stderr
, "session %d not found\n", session_id
);
217 /* if a device ID with a creation date exists, get all group memberships */
218 if (device_id
&& created
)
221 "SELECT group_id FROM groups_members WHERE device_id = ?",
222 DB_INT
, device_id
, DB_INT
);
227 while (e
->enumerate(e
, &group_id
))
229 if (!iterate_enforcements(db
, device_id
, session_id
, group_id
))
240 /* determine if a default product group exists */
242 "SELECT group_id FROM groups_product_defaults "
243 "WHERE product_id = ?", DB_INT
, product_id
, DB_INT
);
248 if (e
->enumerate(e
, &gid
))
254 if (device_id
&& !created
)
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)
261 fprintf(stderr
, "could not assign device to a default group\n");
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)
270 fprintf(stderr
, "creation date of device could not be set\n");
275 return iterate_enforcements(db
, device_id
, session_id
, group_id
);
278 static bool policy_stop(database_t
*db
, int session_id
)
281 int rec
, policy
, final_rec
, id_type
;
283 char *result
, *format
, *ip_address
= NULL
;
287 /* store all workitem results for this session in the results table */
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
);
295 while (e
->enumerate(e
, &rec
, &result
, &policy
))
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
);
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)
317 final_rec
= TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
;
319 /* retrieve the final recommendation for this session */
321 "SELECT rec FROM sessions WHERE id = ?",
322 DB_INT
, session_id
, DB_INT
);
325 if (!e
->enumerate(e
, &final_rec
))
336 /* retrieve client IP address for this session */
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
);
345 if (e
->enumerate(e
, &id_type
, &id_value
))
347 ip_address
= strndup(id_value
.ptr
, id_value
.len
);
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
);
364 if (final_rec
== TNC_IMV_ACTION_RECOMMENDATION_ALLOW
)
366 format
= lib
->settings
->get_str(lib
->settings
,
367 "imv_policy_manager.command_allow", NULL
);
371 format
= lib
->settings
->get_str(lib
->settings
,
372 "imv_policy_manager.command_block", NULL
);
374 if (format
&& ip_address
)
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
);
387 int main(int argc
, char *argv
[])
394 /* enable attest debugging hook */
397 atexit(library_deinit
);
399 /* initialize library */
400 if (!library_init(NULL
, "imv_policy_manager"))
402 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
404 if (!lib
->plugins
->load(lib
->plugins
,
405 lib
->settings
->get_str(lib
->settings
, "imv_policy_manager.load",
408 exit(SS_RC_INITIALIZATION_FAILED
);
414 exit(SS_RC_INITIALIZATION_FAILED
);
416 if (streq(argv
[1], "start"))
420 else if (streq(argv
[1], "stop"))
427 exit(SS_RC_INITIALIZATION_FAILED
);
430 session_id
= atoi(argv
[2]);
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
)));
441 fprintf(stderr
, "database uri not defined.\n");
442 exit(SS_RC_INITIALIZATION_FAILED
);
445 db
= lib
->db
->create(lib
->db
, uri
);
448 fprintf(stderr
, "opening database failed.\n");
449 exit(SS_RC_INITIALIZATION_FAILED
);
454 success
= policy_start(db
, session_id
);
458 success
= policy_stop(db
, session_id
);
462 fprintf(stderr
, "imv_policy_manager %s %s\n", start
? "start" : "stop",
463 success
? "successful" : "failed");