Device can be member of multiple groups
[strongswan.git] / src / libimcv / imv / imv_policy_manager.c
1 /*
2 * Copyright (C) 2013 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 <stdlib.h>
23 #include <stdio.h>
24 #include <time.h>
25
26 /* The default policy group #1 is assumed to always exist */
27 #define DEFAULT_GROUP_ID 1
28
29 /**
30 * global debug output variables
31 */
32 static int debug_level = 1;
33 static bool stderr_quiet = FALSE;
34
35 /**
36 * attest dbg function
37 */
38 static void stderr_dbg(debug_t group, level_t level, char *fmt, ...)
39 {
40 va_list args;
41
42 if (level <= debug_level)
43 {
44 if (!stderr_quiet)
45 {
46 va_start(args, fmt);
47 vfprintf(stderr, fmt, args);
48 fprintf(stderr, "\n");
49 va_end(args);
50 }
51 }
52 }
53
54 /**
55 * Collect all enforcements by iterating up through parent groups
56 */
57 static bool iterate_enforcements(database_t *db, int session_id, int group_id)
58 {
59 int id, type, file, dir, arg_int, rec_fail, rec_noresult, parent;
60 char *argument;
61 enumerator_t *e;
62
63 while (group_id)
64 {
65 e = db->query(db,
66 "SELECT e.id, "
67 "p.type, p.argument, p.file, p.dir, p.rec_fail, p.rec_noresult "
68 "FROM enforcements AS e JOIN policies as p ON e.policy = p.id "
69 "WHERE e.group_id = ?", DB_INT, group_id,
70 DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_INT);
71 if (!e)
72 {
73 return FALSE;
74 }
75 while (e->enumerate(e, &id, &type, &argument, &file, &dir,
76 &rec_fail, &rec_noresult))
77 {
78 /* determine arg_int */
79 switch ((imv_workitem_type_t)type)
80 {
81 case IMV_WORKITEM_FILE_REF_MEAS:
82 case IMV_WORKITEM_FILE_MEAS:
83 case IMV_WORKITEM_FILE_META:
84 arg_int = file;
85 break;
86 case IMV_WORKITEM_DIR_REF_MEAS:
87 case IMV_WORKITEM_DIR_MEAS:
88 case IMV_WORKITEM_DIR_META:
89 arg_int = dir;
90 break;
91 default:
92 arg_int = 0;
93 }
94
95 /* insert a workitem */
96 if (db->execute(db, NULL,
97 "INSERT INTO workitems (session, enforcement, type, arg_str, "
98 "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)",
99 DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument,
100 DB_INT, arg_int, DB_INT, rec_fail, DB_INT, rec_noresult) != 1)
101 {
102 e->destroy(e);
103 fprintf(stderr, "could not insert workitem\n");
104 return FALSE;
105 }
106 }
107 e->destroy(e);
108
109 e = db->query(db,
110 "SELECT parent FROM groups WHERE id = ?",
111 DB_INT, group_id, DB_INT);
112 if (!e)
113 {
114 return FALSE;
115 }
116 if (e->enumerate(e, &parent))
117 {
118 group_id = parent;
119 }
120 else
121 {
122 fprintf(stderr, "group information not found\n");
123 group_id = 0;
124 }
125 e->destroy(e);
126 }
127 return TRUE;
128 }
129
130 static bool policy_start(database_t *db, int session_id)
131 {
132 enumerator_t *e;
133 int device_id, product_id, gid, group_id = DEFAULT_GROUP_ID;
134 u_int created;
135
136 /* get session data */
137 e = db->query(db,
138 "SELECT s.device, s.product, d.created FROM sessions AS s "
139 "LEFT JOIN devices AS d ON s.device = d.id WHERE s.id = ?",
140 DB_INT, session_id, DB_INT, DB_INT, DB_UINT);
141 if (!e || !e->enumerate(e, &device_id, &product_id, &created))
142 {
143 DESTROY_IF(e);
144 fprintf(stderr, "session %d not found\n", session_id);
145 return FALSE;
146 }
147 e->destroy(e);
148
149 /* if a device ID with a creation date exists, get all group memberships */
150 if (device_id & created)
151 {
152 e = db->query(db,
153 "SELECT group_id FROM groups_members WHERE device_id = ?",
154 DB_INT, device_id, DB_INT);
155 if (!e)
156 {
157 return FALSE;
158 }
159 while (e->enumerate(e, &group_id))
160 {
161 if (!iterate_enforcements(db, session_id, group_id))
162 {
163 e->destroy(e);
164 return FALSE;
165 }
166 }
167 e->destroy(e);
168
169 return TRUE;
170 }
171
172 /* determine if a default product group exists */
173 e = db->query(db,
174 "SELECT group_id FROM groups_product_defaults "
175 "WHERE product_id = ?", DB_INT, product_id, DB_INT);
176 if (!e)
177 {
178 return FALSE;
179 }
180 if (e->enumerate(e, &gid))
181 {
182 group_id = gid;
183 }
184 e->destroy(e);
185
186 if (device_id && !created)
187 {
188 /* assign a newly created device to a default group */
189 if (db->execute(db, NULL,
190 "INSERT INTO groups_members (device_id, group_id) "
191 "VALUES (?, ?)", DB_INT, device_id, DB_INT, group_id) != 1)
192 {
193 fprintf(stderr, "could not assign device to a default group\n");
194 return FALSE;
195 }
196
197 /* set the creation date if it hasn't been set yet */
198 if (db->execute(db, NULL,
199 "UPDATE devices SET created = ? WHERE id = ?",
200 DB_UINT, time(NULL), DB_INT, device_id) != 1)
201 {
202 fprintf(stderr, "creation date of device could not be set\n");
203 return FALSE;
204 }
205 }
206
207 return iterate_enforcements(db, session_id, group_id);
208 }
209
210 static bool policy_stop(database_t *db, int session_id)
211 {
212 enumerator_t *e;
213 int rec, policy;
214 char *result;
215
216 e = db->query(db,
217 "SELECT w.rec_final, w.result, e.policy FROM workitems AS w "
218 "JOIN enforcements AS e ON w.enforcement = e.id "
219 "WHERE w.session = ? AND w.result IS NOT NULL",
220 DB_INT, session_id, DB_INT, DB_TEXT, DB_INT);
221 if (e)
222 {
223 while (e->enumerate(e, &rec, &result, &policy))
224 {
225 db->execute(db, NULL,
226 "INSERT INTO results (session, policy, rec, result) "
227 "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy,
228 DB_INT, rec, DB_TEXT, result);
229 }
230 e->destroy(e);
231 }
232 return db->execute(db, NULL,
233 "DELETE FROM workitems WHERE session = ?",
234 DB_UINT, session_id) >= 0;
235 }
236
237 int main(int argc, char *argv[])
238 {
239 database_t *db;
240 char *uri, *tnc_session_id;
241 int session_id;
242 bool start, success;
243
244 /* enable attest debugging hook */
245 dbg = stderr_dbg;
246
247 atexit(library_deinit);
248
249 /* initialize library */
250 if (!library_init(NULL))
251 {
252 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
253 }
254 if (!lib->plugins->load(lib->plugins, NULL,
255 lib->settings->get_str(lib->settings, "imv_policy_manager.load",
256 "sqlite")))
257 {
258 exit(SS_RC_INITIALIZATION_FAILED);
259 }
260
261 if (argc < 2)
262 {
263 usage();
264 exit(SS_RC_INITIALIZATION_FAILED);
265 }
266 if (streq(argv[1], "start"))
267 {
268 start = TRUE;
269 }
270 else if (streq(argv[1], "stop"))
271 {
272 start = FALSE;
273 }
274 else
275 {
276 usage();
277 exit(SS_RC_INITIALIZATION_FAILED);
278 }
279
280 /* get session ID */
281 tnc_session_id = getenv("TNC_SESSION_ID");
282 if (!tnc_session_id)
283 {
284 fprintf(stderr, "environment variable TNC_SESSION_ID is not defined\n");
285 exit(SS_RC_INITIALIZATION_FAILED);
286 }
287 session_id = atoi(tnc_session_id);
288
289 /* attach IMV database */
290 uri = lib->settings->get_str(lib->settings, "libimcv.database", NULL);
291 if (!uri)
292 {
293 fprintf(stderr, "database uri not defined.\n");
294 exit(SS_RC_INITIALIZATION_FAILED);
295 }
296
297 db = lib->db->create(lib->db, uri);
298 if (!db)
299 {
300 fprintf(stderr, "opening database failed.\n");
301 exit(SS_RC_INITIALIZATION_FAILED);
302 }
303
304 if (start)
305 {
306 success = policy_start(db, session_id);
307 }
308 else
309 {
310 success = policy_stop(db, session_id);
311 }
312 db->destroy(db);
313
314 fprintf(stderr, "imv_policy_manager %s %s\n", start ? "start" : "stop",
315 success ? "successful" : "failed");
316
317 exit(EXIT_SUCCESS);
318 }