Annotation of embedaddon/strongswan/src/libimcv/imv/imv_database.c, revision 1.1.1.1
1.1 misho 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: #define _GNU_SOURCE
17:
18: #include <stdio.h>
19: #include <stdarg.h>
20: #include <string.h>
21: #include <time.h>
22:
23: #include "imv_database.h"
24:
25: #include <tncif_identity.h>
26:
27: #include <utils/debug.h>
28: #include <threading/mutex.h>
29:
30: typedef struct private_imv_database_t private_imv_database_t;
31:
32: /**
33: * Private data of a imv_database_t object.
34: */
35: struct private_imv_database_t {
36:
37: /**
38: * Public imv_database_t interface.
39: */
40: imv_database_t public;
41:
42: /**
43: * database instance
44: */
45: database_t *db;
46:
47: /**
48: * policy script
49: */
50: char *script;
51:
52: };
53:
54: METHOD(imv_database_t, get_database, database_t*,
55: private_imv_database_t *this)
56: {
57: return this->db;
58: }
59:
60: /**
61: * Create a session entry in the IMV database
62: */
63: static bool create_session(private_imv_database_t *this, imv_session_t *session)
64: {
65: enumerator_t *enumerator, *e;
66: imv_os_info_t *os_info;
67: chunk_t device_id;
68: tncif_identity_t *tnc_id;
69: TNC_ConnectionID conn_id;
70: char *product, *device;
71: int session_id = 0, pid = 0, did = 0, trusted = 0, created;
72: bool first = TRUE, success = TRUE;
73:
74: /* get product info string */
75: os_info = session->get_os_info(session);
76: product = os_info->get_info(os_info);
77: if (!product)
78: {
79: DBG1(DBG_IMV, "imv_db: product info is not available");
80: return FALSE;
81: }
82:
83: /* get primary key of product info string if it exists */
84: e = this->db->query(this->db,
85: "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT);
86: if (e)
87: {
88: e->enumerate(e, &pid);
89: e->destroy(e);
90: }
91:
92: /* if product info string has not been found - register it */
93: if (!pid)
94: {
95: this->db->execute(this->db, &pid,
96: "INSERT INTO products (name) VALUES (?)", DB_TEXT, product);
97: }
98:
99: if (!pid)
100: {
101: DBG1(DBG_IMV, "imv_db: registering product info failed");
102: return FALSE;
103: }
104:
105: /* get device ID string */
106: if (!session->get_device_id(session, &device_id))
107: {
108: DBG1(DBG_IMV, "imv_db: device ID is not available");
109: return FALSE;
110: }
111: device = strndup(device_id.ptr, device_id.len);
112:
113: /* get primary key of device ID if it exists */
114: e = this->db->query(this->db,
115: "SELECT id, trusted FROM devices WHERE value = ? AND product = ?",
116: DB_TEXT, device, DB_INT, pid, DB_INT, DB_INT);
117: if (e)
118: {
119: e->enumerate(e, &did, &trusted);
120: e->destroy(e);
121: }
122:
123: /* if device ID is trusted, set trust in session */
124: if (trusted)
125: {
126: session->set_device_trust(session, TRUE);
127: }
128:
129: /* if device ID has not been found - register it */
130: if (!did)
131: {
132: this->db->execute(this->db, &did,
133: "INSERT INTO devices "
134: "(value, description, product, trusted, inactive) "
135: "VALUES (?, '', ?, 0, 0)", DB_TEXT, device, DB_INT, pid);
136: }
137: free(device);
138:
139: if (!did)
140: {
141: DBG1(DBG_IMV, "imv_db: registering device ID failed");
142: return FALSE;
143: }
144:
145: /* create a new session entry */
146: created = time(NULL);
147: conn_id = session->get_connection_id(session);
148: this->db->execute(this->db, &session_id,
149: "INSERT INTO sessions (time, connection, product, device) "
150: "VALUES (?, ?, ?, ?)",
151: DB_INT, created, DB_INT, conn_id, DB_INT, pid, DB_INT, did);
152:
153: if (session_id)
154: {
155: DBG2(DBG_IMV, "assigned session ID %d to Connection ID %d",
156: session_id, conn_id);
157: }
158: else
159: {
160: DBG1(DBG_IMV, "imv_db: registering session failed");
161: return FALSE;
162: }
163: session->set_session_id(session, session_id, pid, did);
164: session->set_creation_time(session, created);
165:
166: enumerator = session->create_ar_identities_enumerator(session);
167: while (enumerator->enumerate(enumerator, &tnc_id))
168: {
169: pen_type_t ar_id_type;
170: chunk_t ar_id_value;
171: int ar_id = 0, si_id = 0;
172:
173: ar_id_type = tnc_id->get_identity_type(tnc_id);
174: ar_id_value = tnc_id->get_identity_value(tnc_id);
175:
176: if (ar_id_type.vendor_id != PEN_TCG || ar_id_value.len == 0)
177: {
178: continue;
179: }
180:
181: /* get primary key of AR identity if it exists */
182: e = this->db->query(this->db,
183: "SELECT id FROM identities WHERE type = ? AND value = ?",
184: DB_INT, ar_id_type.type, DB_BLOB, ar_id_value, DB_INT);
185: if (e)
186: {
187: e->enumerate(e, &ar_id);
188: e->destroy(e);
189: }
190:
191: /* if AR identity has not been found - register it */
192: if (!ar_id)
193: {
194: this->db->execute(this->db, &ar_id,
195: "INSERT INTO identities (type, value) VALUES (?, ?)",
196: DB_INT, ar_id_type.type, DB_BLOB, ar_id_value);
197: }
198: if (!ar_id)
199: {
200: DBG1(DBG_IMV, "imv_db: registering access requestor failed");
201: success = FALSE;
202: break;
203: }
204:
205: this->db->execute(this->db, &si_id,
206: "INSERT INTO sessions_identities (session_id, identity_id) "
207: "VALUES (?, ?)",
208: DB_INT, session_id, DB_INT, ar_id);
209:
210: if (!si_id)
211: {
212: DBG1(DBG_IMV, "imv_db: assigning identity to session failed");
213: success = FALSE;
214: break;
215: }
216:
217: if (first)
218: {
219: this->db->execute(this->db, NULL,
220: "UPDATE sessions SET identity = ? WHERE id = ?",
221: DB_INT, ar_id, DB_INT, session_id);
222: first = FALSE;
223: }
224: }
225: enumerator->destroy(enumerator);
226:
227: return success;
228: }
229:
230: static bool add_workitems(private_imv_database_t *this, imv_session_t *session)
231: {
232: char *arg_str;
233: int id, arg_int, rec_fail, rec_noresult;
234: imv_workitem_t *workitem;
235: imv_workitem_type_t type;
236: enumerator_t *e;
237:
238: e = this->db->query(this->db,
239: "SELECT id, type, arg_str, arg_int, rec_fail, rec_noresult "
240: "FROM workitems WHERE session = ?",
241: DB_INT, session->get_session_id(session, NULL, NULL),
242: DB_INT, DB_INT, DB_TEXT, DB_INT,DB_INT, DB_INT);
243: if (!e)
244: {
245: DBG1(DBG_IMV, "imv_db: no workitem enumerator returned");
246: return FALSE;
247: }
248: while (e->enumerate(e, &id, &type, &arg_str, &arg_int, &rec_fail,
249: &rec_noresult))
250: {
251: DBG2(DBG_IMV, "%N workitem %d", imv_workitem_type_names, type, id);
252: workitem = imv_workitem_create(id, type, arg_str, arg_int, rec_fail,
253: rec_noresult);
254: session->insert_workitem(session, workitem);
255: }
256: e->destroy(e);
257:
258: return TRUE;
259: }
260:
261: METHOD(imv_database_t, add_recommendation, void,
262: private_imv_database_t *this, imv_session_t *session,
263: TNC_IMV_Action_Recommendation rec)
264: {
265: /* add final recommendation to session DB entry */
266: this->db->execute(this->db, NULL,
267: "UPDATE sessions SET rec = ? WHERE id = ?",
268: DB_INT, rec, DB_INT, session->get_session_id(session, NULL, NULL));
269: }
270:
271: METHOD(imv_database_t, policy_script, bool,
272: private_imv_database_t *this, imv_session_t *session, bool start)
273: {
274: char command[512], resp[128], *last;
275: FILE *shell;
276:
277: if (start)
278: {
279: if (session->get_policy_started(session))
280: {
281: DBG1(DBG_IMV, "policy script as already been started");
282: return FALSE;
283: }
284:
285: /* add product info and device ID to session DB entry */
286: if (!create_session(this, session))
287: {
288: return FALSE;
289: }
290: }
291: else
292: {
293: if (!session->get_policy_started(session))
294: {
295: DBG1(DBG_IMV, "policy script as already been stopped");
296: return FALSE;
297: }
298: }
299:
300: /* call the policy script */
301: snprintf(command, sizeof(command), "2>&1 %s %s %d",
302: this->script, start ? "start" : "stop",
303: session->get_session_id(session, NULL, NULL));
304: DBG3(DBG_IMV, "running policy script: %s", command);
305:
306: shell = popen(command, "r");
307: if (shell == NULL)
308: {
309: DBG1(DBG_IMV, "could not execute policy script '%s'",
310: this->script);
311: return FALSE;
312: }
313: while (TRUE)
314: {
315: if (fgets(resp, sizeof(resp), shell) == NULL)
316: {
317: if (ferror(shell))
318: {
319: DBG1(DBG_IMV, "error reading output from policy script");
320: }
321: break;
322: }
323: else
324: {
325: last = resp + strlen(resp) - 1;
326: if (last >= resp && *last == '\n')
327: {
328: /* replace trailing '\n' */
329: *last = '\0';
330: }
331: DBG1(DBG_IMV, "policy: %s", resp);
332: }
333: }
334: pclose(shell);
335:
336: if (start)
337: {
338: /* add workitem list generated by policy manager to session object */
339: if (!add_workitems(this, session))
340: {
341: return FALSE;
342: }
343: session->set_policy_started(session, TRUE);
344: }
345: else
346: {
347: session->set_policy_started(session, FALSE);
348: }
349:
350: return TRUE;
351: }
352:
353: METHOD(imv_database_t, finalize_workitem, bool,
354: private_imv_database_t *this, imv_workitem_t *workitem)
355: {
356: char *result;
357: int rec;
358:
359: rec = workitem->get_result(workitem, &result);
360:
361: return this->db->execute(this->db, NULL,
362: "UPDATE workitems SET result = ?, rec_final = ? WHERE id = ?",
363: DB_TEXT, result, DB_INT, rec,
364: DB_INT, workitem->get_id(workitem)) == 1;
365: }
366:
367: METHOD(imv_database_t, destroy, void,
368: private_imv_database_t *this)
369: {
370: DESTROY_IF(this->db);
371: free(this);
372: }
373:
374: /**
375: * See header
376: */
377: imv_database_t *imv_database_create(char *uri, char *script)
378: {
379: private_imv_database_t *this;
380:
381: INIT(this,
382: .public = {
383: .get_database = _get_database,
384: .policy_script = _policy_script,
385: .finalize_workitem = _finalize_workitem,
386: .add_recommendation = _add_recommendation,
387: .destroy = _destroy,
388: },
389: .db = lib->db->create(lib->db, uri),
390: .script = script,
391: );
392:
393: if (!this->db)
394: {
395: DBG1(DBG_IMV,
396: "failed to connect to IMV database '%s'", uri);
397: destroy(this);
398: return NULL;
399: }
400:
401: return &this->public;
402: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>