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 enforcment %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
:
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)
146 fprintf(stderr
, "could not insert workitem\n");
153 "SELECT parent FROM groups WHERE id = ?",
154 DB_INT
, group_id
, DB_INT
);
159 if (e
->enumerate(e
, &parent
))
165 fprintf(stderr
, "group information not found\n");
173 static bool policy_start(database_t
*db
, int session_id
)
176 int device_id
, product_id
, gid
, group_id
= DEFAULT_GROUP_ID
;
179 /* get session data */
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
))
187 fprintf(stderr
, "session %d not found\n", session_id
);
192 /* if a device ID with a creation date exists, get all group memberships */
193 if (device_id
&& created
)
196 "SELECT group_id FROM groups_members WHERE device_id = ?",
197 DB_INT
, device_id
, DB_INT
);
202 while (e
->enumerate(e
, &group_id
))
204 if (!iterate_enforcements(db
, device_id
, session_id
, group_id
))
215 /* determine if a default product group exists */
217 "SELECT group_id FROM groups_product_defaults "
218 "WHERE product_id = ?", DB_INT
, product_id
, DB_INT
);
223 if (e
->enumerate(e
, &gid
))
229 if (device_id
&& !created
)
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)
236 fprintf(stderr
, "could not assign device to a default group\n");
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)
245 fprintf(stderr
, "creation date of device could not be set\n");
250 return iterate_enforcements(db
, device_id
, session_id
, group_id
);
253 static bool policy_stop(database_t
*db
, int session_id
)
256 int rec
, policy
, final_rec
, id_type
;
258 char *result
, *format
, *ip_address
= NULL
;
262 /* store all workitem results for this session in the results table */
264 "SELECT w.rec_final, w.result, e.policy FROM workitems AS w "
265 "JOIN enforcements AS e ON w.enforcement = e.id "
266 "WHERE w.session = ? AND w.result IS NOT NULL",
267 DB_INT
, session_id
, DB_INT
, DB_TEXT
, DB_INT
);
270 while (e
->enumerate(e
, &rec
, &result
, &policy
))
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
);
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)
292 final_rec
= TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
;
294 /* retrieve the final recommendation for this session */
296 "SELECT rec FROM sessions WHERE id = ?",
297 DB_INT
, session_id
, DB_INT
);
300 if (!e
->enumerate(e
, &final_rec
))
311 /* retrieve client IP address for this session */
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
);
320 if (e
->enumerate(e
, &id_type
, &id_value
))
322 ip_address
= strndup(id_value
.ptr
, id_value
.len
);
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
);
339 if (final_rec
== TNC_IMV_ACTION_RECOMMENDATION_ALLOW
)
341 format
= lib
->settings
->get_str(lib
->settings
,
342 "imv_policy_manager.command_allow", NULL
);
346 format
= lib
->settings
->get_str(lib
->settings
,
347 "imv_policy_manager.command_block", NULL
);
349 if (format
&& ip_address
)
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
);
362 int main(int argc
, char *argv
[])
369 /* enable attest debugging hook */
372 atexit(library_deinit
);
374 /* initialize library */
375 if (!library_init(NULL
, "imv_policy_manager"))
377 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
379 if (!lib
->plugins
->load(lib
->plugins
,
380 lib
->settings
->get_str(lib
->settings
, "imv_policy_manager.load",
383 exit(SS_RC_INITIALIZATION_FAILED
);
389 exit(SS_RC_INITIALIZATION_FAILED
);
391 if (streq(argv
[1], "start"))
395 else if (streq(argv
[1], "stop"))
402 exit(SS_RC_INITIALIZATION_FAILED
);
405 session_id
= atoi(argv
[2]);
407 /* attach IMV database */
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
)));
416 fprintf(stderr
, "database uri not defined.\n");
417 exit(SS_RC_INITIALIZATION_FAILED
);
420 db
= lib
->db
->create(lib
->db
, uri
);
423 fprintf(stderr
, "opening database failed.\n");
424 exit(SS_RC_INITIALIZATION_FAILED
);
429 success
= policy_start(db
, session_id
);
433 success
= policy_stop(db
, session_id
);
437 fprintf(stderr
, "imv_policy_manager %s %s\n", start
? "start" : "stop",
438 success
? "successful" : "failed");