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
23 #include "imv_database.h"
25 #include <tncif_identity.h>
27 #include <utils/debug.h>
28 #include <threading/mutex.h>
30 typedef struct private_imv_database_t private_imv_database_t
;
33 * Private data of a imv_database_t object.
35 struct private_imv_database_t
{
38 * Public imv_database_t interface.
40 imv_database_t
public;
54 METHOD(imv_database_t
, get_database
, database_t
*,
55 private_imv_database_t
*this)
61 * Create a session entry in the IMV database
63 static bool create_session(private_imv_database_t
*this, imv_session_t
*session
)
65 enumerator_t
*enumerator
, *e
;
66 imv_os_info_t
*os_info
;
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
;
74 /* get product info string */
75 os_info
= session
->get_os_info(session
);
76 product
= os_info
->get_info(os_info
);
79 DBG1(DBG_IMV
, "imv_db: product info is not available");
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
);
88 e
->enumerate(e
, &pid
);
92 /* if product info string has not been found - register it */
95 this->db
->execute(this->db
, &pid
,
96 "INSERT INTO products (name) VALUES (?)", DB_TEXT
, product
);
101 DBG1(DBG_IMV
, "imv_db: registering product info failed");
105 /* get device ID string */
106 if (!session
->get_device_id(session
, &device_id
))
108 DBG1(DBG_IMV
, "imv_db: device ID is not available");
111 device
= strndup(device_id
.ptr
, device_id
.len
);
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
);
119 e
->enumerate(e
, &did
, &trusted
);
123 /* if device ID is trusted, set trust in session */
126 session
->set_device_trust(session
, TRUE
);
129 /* if device ID has not been found - register it */
132 this->db
->execute(this->db
, &did
,
133 "INSERT INTO devices (value, product) VALUES (?, ?)",
134 DB_TEXT
, device
, DB_INT
, pid
);
140 DBG1(DBG_IMV
, "imv_db: registering device ID failed");
144 /* create a new session entry */
145 created
= session
->get_creation_time(session
);
146 conn_id
= session
->get_connection_id(session
);
147 this->db
->execute(this->db
, &session_id
,
148 "INSERT INTO sessions (time, connection, product, device) "
149 "VALUES (?, ?, ?, ?)",
150 DB_INT
, created
, DB_INT
, conn_id
, DB_INT
, pid
, DB_INT
, did
);
154 DBG2(DBG_IMV
, "assigned session ID %d to Connection ID %d",
155 session_id
, conn_id
);
159 DBG1(DBG_IMV
, "imv_db: registering session failed");
162 session
->set_session_id(session
, session_id
, pid
, did
);
164 enumerator
= session
->create_ar_identities_enumerator(session
);
165 while (enumerator
->enumerate(enumerator
, &tnc_id
))
167 pen_type_t ar_id_type
;
169 int ar_id
= 0, si_id
= 0;
171 ar_id_type
= tnc_id
->get_identity_type(tnc_id
);
172 ar_id_value
= tnc_id
->get_identity_value(tnc_id
);
174 if (ar_id_type
.vendor_id
!= PEN_TCG
|| ar_id_value
.len
== 0)
179 /* get primary key of AR identity if it exists */
180 e
= this->db
->query(this->db
,
181 "SELECT id FROM identities WHERE type = ? AND value = ?",
182 DB_INT
, ar_id_type
.type
, DB_BLOB
, ar_id_value
, DB_INT
);
185 e
->enumerate(e
, &ar_id
);
189 /* if AR identity has not been found - register it */
192 this->db
->execute(this->db
, &ar_id
,
193 "INSERT INTO identities (type, value) VALUES (?, ?)",
194 DB_INT
, ar_id_type
.type
, DB_BLOB
, ar_id_value
);
198 DBG1(DBG_IMV
, "imv_db: registering access requestor failed");
203 this->db
->execute(this->db
, &si_id
,
204 "INSERT INTO sessions_identities (session_id, identity_id) "
206 DB_INT
, session_id
, DB_INT
, ar_id
);
210 DBG1(DBG_IMV
, "imv_db: assigning identity to session failed");
217 this->db
->execute(this->db
, NULL
,
218 "UPDATE sessions SET identity = ? WHERE id = ?",
219 DB_INT
, ar_id
, DB_INT
, session_id
);
223 enumerator
->destroy(enumerator
);
228 static bool add_workitems(private_imv_database_t
*this, imv_session_t
*session
)
231 int id
, arg_int
, rec_fail
, rec_noresult
;
232 imv_workitem_t
*workitem
;
233 imv_workitem_type_t type
;
236 e
= this->db
->query(this->db
,
237 "SELECT id, type, arg_str, arg_int, rec_fail, rec_noresult "
238 "FROM workitems WHERE session = ?",
239 DB_INT
, session
->get_session_id(session
, NULL
, NULL
),
240 DB_INT
, DB_INT
, DB_TEXT
, DB_INT
,DB_INT
, DB_INT
);
243 DBG1(DBG_IMV
, "imv_db: no workitem enumerator returned");
246 while (e
->enumerate(e
, &id
, &type
, &arg_str
, &arg_int
, &rec_fail
,
249 DBG2(DBG_IMV
, "%N workitem %d", imv_workitem_type_names
, type
, id
);
250 workitem
= imv_workitem_create(id
, type
, arg_str
, arg_int
, rec_fail
,
252 session
->insert_workitem(session
, workitem
);
259 METHOD(imv_database_t
, add_recommendation
, void,
260 private_imv_database_t
*this, imv_session_t
*session
,
261 TNC_IMV_Action_Recommendation rec
)
263 /* add final recommendation to session DB entry */
264 this->db
->execute(this->db
, NULL
,
265 "UPDATE sessions SET rec = ? WHERE id = ?",
266 DB_INT
, rec
, DB_INT
, session
->get_session_id(session
, NULL
, NULL
));
269 METHOD(imv_database_t
, policy_script
, bool,
270 private_imv_database_t
*this, imv_session_t
*session
, bool start
)
272 char command
[512], resp
[128], *last
;
277 if (session
->get_policy_started(session
))
279 DBG1(DBG_IMV
, "policy script as already been started");
283 /* add product info and device ID to session DB entry */
284 if (!create_session(this, session
))
291 if (!session
->get_policy_started(session
))
293 DBG1(DBG_IMV
, "policy script as already been stopped");
298 /* call the policy script */
299 snprintf(command
, sizeof(command
), "2>&1 %s %s %d",
300 this->script
, start
? "start" : "stop",
301 session
->get_session_id(session
, NULL
, NULL
));
302 DBG3(DBG_IMV
, "running policy script: %s", command
);
304 shell
= popen(command
, "r");
307 DBG1(DBG_IMV
, "could not execute policy script '%s'",
313 if (fgets(resp
, sizeof(resp
), shell
) == NULL
)
317 DBG1(DBG_IMV
, "error reading output from policy script");
323 last
= resp
+ strlen(resp
) - 1;
324 if (last
>= resp
&& *last
== '\n')
326 /* replace trailing '\n' */
329 DBG1(DBG_IMV
, "policy: %s", resp
);
336 /* add workitem list generated by policy manager to session object */
337 if (!add_workitems(this, session
))
341 session
->set_policy_started(session
, TRUE
);
345 session
->set_policy_started(session
, FALSE
);
351 METHOD(imv_database_t
, finalize_workitem
, bool,
352 private_imv_database_t
*this, imv_workitem_t
*workitem
)
357 rec
= workitem
->get_result(workitem
, &result
);
359 return this->db
->execute(this->db
, NULL
,
360 "UPDATE workitems SET result = ?, rec_final = ? WHERE id = ?",
361 DB_TEXT
, result
, DB_INT
, rec
,
362 DB_INT
, workitem
->get_id(workitem
)) == 1;
365 METHOD(imv_database_t
, destroy
, void,
366 private_imv_database_t
*this)
368 DESTROY_IF(this->db
);
375 imv_database_t
*imv_database_create(char *uri
, char *script
)
377 private_imv_database_t
*this;
381 .get_database
= _get_database
,
382 .policy_script
= _policy_script
,
383 .finalize_workitem
= _finalize_workitem
,
384 .add_recommendation
= _add_recommendation
,
387 .db
= lib
->db
->create(lib
->db
, uri
),
394 "failed to connect to IMV database '%s'", uri
);
399 return &this->public;