]>
Commit | Line | Data |
---|---|---|
e881ee23 | 1 | /* |
60da0153 | 2 | * Copyright (C) 2011-2017 Andreas Steffen |
e881ee23 AS |
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 | ||
b8db66de AS |
16 | #define _GNU_SOURCE |
17 | ||
18 | #include <stdio.h> | |
19 | #include <libgen.h> | |
20 | #include <time.h> | |
21 | ||
29645621 AS |
22 | #include <tncif_names.h> |
23 | ||
e881ee23 AS |
24 | #include "attest_db.h" |
25 | ||
d6fb2cc6 | 26 | #include "imcv.h" |
358dbe48 | 27 | #include "pts/pts_meas_algo.h" |
0f236aac | 28 | #include "pts/pts_file_meas.h" |
6b55276a | 29 | #include "pts/components/pts_comp_func_name.h" |
72631301 | 30 | |
358dbe48 | 31 | #define IMA_MAX_NAME_LEN 255 |
72631301 | 32 | #define DEVICE_MAX_LEN 20 |
358dbe48 | 33 | |
e881ee23 AS |
34 | typedef struct private_attest_db_t private_attest_db_t; |
35 | ||
36 | /** | |
37 | * Private data of an attest_db_t object. | |
38 | */ | |
39 | struct private_attest_db_t { | |
40 | ||
41 | /** | |
42 | * Public members of attest_db_state_t | |
43 | */ | |
44 | attest_db_t public; | |
45 | ||
46 | /** | |
f2a521e7 | 47 | * Component Functional Name to be queried |
e881ee23 | 48 | */ |
f2a521e7 | 49 | pts_comp_func_name_t *cfn; |
e881ee23 AS |
50 | |
51 | /** | |
f2a521e7 | 52 | * Primary key of the Component Functional Name to be queried |
e881ee23 | 53 | */ |
f2a521e7 | 54 | int cid; |
e881ee23 AS |
55 | |
56 | /** | |
f2a521e7 | 57 | * TRUE if Component Functional Name has been set |
e881ee23 | 58 | */ |
f2a521e7 AS |
59 | bool comp_set; |
60 | ||
61 | /** | |
62 | * Directory containing the Measurement file to be queried | |
63 | */ | |
64 | char *dir; | |
65 | ||
66 | /** | |
67 | * Primary key of the directory to be queried | |
68 | */ | |
69 | int did; | |
70 | ||
e881ee23 AS |
71 | /** |
72 | * Measurement file to be queried | |
73 | */ | |
74 | char *file; | |
75 | ||
76 | /** | |
77 | * Primary key of measurement file to be queried | |
78 | */ | |
79 | int fid; | |
80 | ||
37a73b9c AS |
81 | /** |
82 | * Directory where file measurement are to be taken | |
83 | */ | |
84 | char *meas_dir; | |
85 | ||
e881ee23 | 86 | /** |
f2a521e7 | 87 | * AIK to be queried |
e881ee23 | 88 | */ |
f2a521e7 | 89 | chunk_t key; |
e881ee23 AS |
90 | |
91 | /** | |
f2a521e7 | 92 | * Primary key of the AIK to be queried |
e881ee23 | 93 | */ |
f2a521e7 | 94 | int kid; |
e881ee23 AS |
95 | |
96 | /** | |
f2a521e7 | 97 | * TRUE if AIK has been set |
e881ee23 | 98 | */ |
f2a521e7 | 99 | bool key_set; |
e881ee23 | 100 | |
1bb6a086 AS |
101 | /** |
102 | * Software package to be queried | |
103 | */ | |
104 | char *package; | |
105 | ||
106 | /** | |
107 | * Primary key of software package to be queried | |
108 | */ | |
109 | int gid; | |
110 | ||
111 | /** | |
112 | * TRUE if package has been set | |
113 | */ | |
114 | bool package_set; | |
115 | ||
d37abe0f | 116 | /** |
f2a521e7 | 117 | * Software product to be queried |
d37abe0f | 118 | */ |
f2a521e7 | 119 | char *product; |
d37abe0f AS |
120 | |
121 | /** | |
f2a521e7 | 122 | * Primary key of software product to be queried |
d37abe0f | 123 | */ |
f2a521e7 | 124 | int pid; |
d37abe0f AS |
125 | |
126 | /** | |
f2a521e7 | 127 | * TRUE if product has been set |
d37abe0f | 128 | */ |
f2a521e7 | 129 | bool product_set; |
d37abe0f | 130 | |
1bb6a086 AS |
131 | /** |
132 | * Software package version to be queried | |
133 | */ | |
134 | char *version; | |
135 | ||
60da0153 AS |
136 | /** |
137 | * Primary key of software package version to be queried | |
138 | */ | |
139 | int vid; | |
140 | ||
1bb6a086 AS |
141 | /** |
142 | * TRUE if version has been set | |
143 | */ | |
144 | bool version_set; | |
145 | ||
0f236aac AS |
146 | /** |
147 | * TRUE if relative filenames are to be used | |
148 | */ | |
149 | bool relative; | |
150 | ||
81ee269d AS |
151 | /** |
152 | * TRUE if dates are to be displayed in UTC | |
153 | */ | |
154 | bool utc; | |
155 | ||
1bb6a086 | 156 | /** |
71c7b435 | 157 | * Package security or blacklist state |
1bb6a086 | 158 | */ |
71c7b435 | 159 | os_package_state_t package_state; |
1bb6a086 | 160 | |
e0c66beb AS |
161 | /** |
162 | * Sequence number for ordering entries | |
163 | */ | |
164 | int seq_no; | |
165 | ||
e881ee23 AS |
166 | /** |
167 | * File measurement hash algorithm | |
168 | */ | |
169 | pts_meas_algorithms_t algo; | |
170 | ||
f2a521e7 AS |
171 | /** |
172 | * Optional owner (user/host name) | |
173 | */ | |
174 | char *owner; | |
175 | ||
e881ee23 AS |
176 | /** |
177 | * Attestation database | |
178 | */ | |
179 | database_t *db; | |
180 | ||
181 | }; | |
182 | ||
d37abe0f AS |
183 | char* print_cfn(pts_comp_func_name_t *cfn) |
184 | { | |
185 | static char buf[BUF_LEN]; | |
186 | char flags[8]; | |
187 | int type, vid, name, qualifier, n; | |
188 | enum_name_t *names, *types; | |
189 | ||
f1889ca3 | 190 | vid = cfn->get_vendor_id(cfn); |
d37abe0f AS |
191 | name = cfn->get_name(cfn); |
192 | qualifier = cfn->get_qualifier(cfn); | |
193 | n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier); | |
194 | ||
d6fb2cc6 AS |
195 | names = imcv_pts_components->get_comp_func_names(imcv_pts_components, vid); |
196 | types = imcv_pts_components->get_qualifier_type_names(imcv_pts_components, | |
197 | vid); | |
198 | type = imcv_pts_components->get_qualifier(imcv_pts_components, cfn, flags); | |
d37abe0f AS |
199 | if (names && types) |
200 | { | |
201 | n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N", | |
202 | pen_names, vid, names, name, flags, types, type); | |
203 | } | |
204 | return buf; | |
205 | } | |
206 | ||
0731d41c MW |
207 | /** |
208 | * Get the directory separator to append to a path | |
209 | */ | |
210 | static const char* get_separator(const char *path) | |
211 | { | |
212 | if (streq(path, DIRECTORY_SEPARATOR)) | |
213 | { /* root directory on Unix file system, no separator */ | |
214 | return ""; | |
215 | } | |
216 | else | |
217 | { /* non-root or Windows path, use system specific separator */ | |
218 | return DIRECTORY_SEPARATOR; | |
219 | } | |
220 | } | |
221 | ||
f2a521e7 AS |
222 | METHOD(attest_db_t, set_component, bool, |
223 | private_attest_db_t *this, char *comp, bool create) | |
e881ee23 AS |
224 | { |
225 | enumerator_t *e; | |
f2a521e7 AS |
226 | char *pos1, *pos2; |
227 | int vid, name, qualifier; | |
228 | pts_comp_func_name_t *cfn; | |
e881ee23 | 229 | |
f2a521e7 | 230 | if (this->comp_set) |
e881ee23 | 231 | { |
f2a521e7 | 232 | printf("component has already been set\n"); |
e881ee23 AS |
233 | return FALSE; |
234 | } | |
e881ee23 | 235 | |
f2a521e7 AS |
236 | /* parse component string */ |
237 | pos1 = strchr(comp, '/'); | |
238 | pos2 = strchr(comp, '-'); | |
239 | if (!pos1 || !pos2) | |
240 | { | |
241 | printf("component string must have the form \"vendor_id/name-qualifier\"\n"); | |
242 | return FALSE; | |
243 | } | |
244 | vid = atoi(comp); | |
245 | name = atoi(pos1 + 1); | |
246 | qualifier = atoi(pos2 + 1); | |
247 | cfn = pts_comp_func_name_create(vid, name, qualifier); | |
248 | ||
249 | e = this->db->query(this->db, | |
250 | "SELECT id FROM components " | |
251 | "WHERE vendor_id = ? AND name = ? AND qualifier = ?", | |
e0c66beb | 252 | DB_UINT, vid, DB_INT, name, DB_INT, qualifier, DB_INT); |
e881ee23 AS |
253 | if (e) |
254 | { | |
f2a521e7 | 255 | if (e->enumerate(e, &this->cid)) |
e881ee23 | 256 | { |
f2a521e7 AS |
257 | this->comp_set = TRUE; |
258 | this->cfn = cfn; | |
e881ee23 | 259 | } |
e881ee23 AS |
260 | e->destroy(e); |
261 | } | |
f2a521e7 | 262 | if (this->comp_set) |
f4159ff8 AS |
263 | { |
264 | return TRUE; | |
265 | } | |
266 | ||
267 | if (!create) | |
268 | { | |
f2a521e7 AS |
269 | printf("component '%s' not found in database\n", print_cfn(cfn)); |
270 | cfn->destroy(cfn); | |
2b28a131 | 271 | return FALSE; |
f4159ff8 AS |
272 | } |
273 | ||
274 | /* Add a new database entry */ | |
f2a521e7 AS |
275 | this->comp_set = this->db->execute(this->db, &this->cid, |
276 | "INSERT INTO components (vendor_id, name, qualifier) " | |
277 | "VALUES (?, ?, ?)", | |
278 | DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1; | |
f4159ff8 | 279 | |
f2a521e7 AS |
280 | printf("component '%s' %sinserted into database\n", print_cfn(cfn), |
281 | this->comp_set ? "" : "could not be "); | |
282 | if (this->comp_set) | |
283 | { | |
284 | this->cfn = cfn; | |
285 | } | |
286 | else | |
287 | { | |
288 | cfn->destroy(cfn); | |
289 | } | |
290 | return this->comp_set; | |
291 | } | |
f4159ff8 | 292 | |
f2a521e7 AS |
293 | METHOD(attest_db_t, set_cid, bool, |
294 | private_attest_db_t *this, int cid) | |
295 | { | |
296 | enumerator_t *e; | |
297 | int vid, name, qualifier; | |
298 | ||
299 | if (this->comp_set) | |
300 | { | |
301 | printf("component has already been set\n"); | |
302 | return FALSE; | |
303 | } | |
304 | this->cid = cid; | |
305 | ||
306 | e = this->db->query(this->db, "SELECT vendor_id, name, qualifier " | |
307 | "FROM components WHERE id = ?", | |
e0c66beb | 308 | DB_UINT, cid, DB_INT, DB_INT, DB_INT); |
f2a521e7 AS |
309 | if (e) |
310 | { | |
311 | if (e->enumerate(e, &vid, &name, &qualifier)) | |
312 | { | |
313 | this->cfn = pts_comp_func_name_create(vid, name, qualifier); | |
314 | this->comp_set = TRUE; | |
315 | } | |
316 | else | |
317 | { | |
318 | printf("no component found with cid %d\n", cid); | |
319 | } | |
320 | e->destroy(e); | |
321 | } | |
322 | return this->comp_set; | |
e881ee23 AS |
323 | } |
324 | ||
f2a521e7 AS |
325 | METHOD(attest_db_t, set_directory, bool, |
326 | private_attest_db_t *this, char *dir, bool create) | |
e881ee23 AS |
327 | { |
328 | enumerator_t *e; | |
1f179c63 | 329 | int did; |
0f236aac | 330 | size_t len; |
e881ee23 | 331 | |
1f179c63 | 332 | if (this->did) |
e881ee23 | 333 | { |
f2a521e7 | 334 | printf("directory has already been set\n"); |
e881ee23 AS |
335 | return FALSE; |
336 | } | |
0f236aac | 337 | |
0731d41c | 338 | /* remove trailing '/' or '\' character if not root directory */ |
0f236aac | 339 | len = strlen(dir); |
0731d41c | 340 | if (len > 1 && dir[len-1] == DIRECTORY_SEPARATOR[0]) |
0f236aac AS |
341 | { |
342 | dir[len-1] = '\0'; | |
343 | } | |
f2a521e7 | 344 | this->dir = strdup(dir); |
e881ee23 | 345 | |
f2a521e7 | 346 | e = this->db->query(this->db, |
1f179c63 | 347 | "SELECT id FROM directories WHERE path = ?", |
f2a521e7 | 348 | DB_TEXT, dir, DB_INT); |
e881ee23 AS |
349 | if (e) |
350 | { | |
1f179c63 | 351 | if (e->enumerate(e, &did)) |
e881ee23 | 352 | { |
1f179c63 | 353 | this->did = did; |
f2a521e7 AS |
354 | } |
355 | e->destroy(e); | |
356 | } | |
1f179c63 | 357 | if (this->did) |
f2a521e7 AS |
358 | { |
359 | return TRUE; | |
360 | } | |
361 | ||
362 | if (!create) | |
363 | { | |
364 | printf("directory '%s' not found in database\n", dir); | |
365 | return FALSE; | |
366 | } | |
367 | ||
368 | /* Add a new database entry */ | |
1f179c63 AS |
369 | if (1 == this->db->execute(this->db, &did, |
370 | "INSERT INTO directories (path) VALUES (?)", DB_TEXT, dir)) | |
371 | { | |
372 | this->did = did; | |
373 | } | |
f2a521e7 | 374 | printf("directory '%s' %sinserted into database\n", dir, |
1f179c63 | 375 | this->did ? "" : "could not be "); |
f2a521e7 | 376 | |
1f179c63 | 377 | return this->did > 0; |
f2a521e7 AS |
378 | } |
379 | ||
380 | METHOD(attest_db_t, set_did, bool, | |
381 | private_attest_db_t *this, int did) | |
382 | { | |
383 | enumerator_t *e; | |
384 | char *dir; | |
385 | ||
1f179c63 | 386 | if (this->did) |
f2a521e7 AS |
387 | { |
388 | printf("directory has already been set\n"); | |
389 | return FALSE; | |
390 | } | |
f2a521e7 | 391 | |
1f179c63 | 392 | e = this->db->query(this->db, "SELECT path FROM directories WHERE id = ?", |
e0c66beb | 393 | DB_UINT, did, DB_TEXT); |
f2a521e7 AS |
394 | if (e) |
395 | { | |
396 | if (e->enumerate(e, &dir)) | |
397 | { | |
f2a521e7 | 398 | this->dir = strdup(dir); |
1f179c63 | 399 | this->did = did; |
e881ee23 AS |
400 | } |
401 | else | |
402 | { | |
f2a521e7 | 403 | printf("no directory found with did %d\n", did); |
e881ee23 AS |
404 | } |
405 | e->destroy(e); | |
406 | } | |
1f179c63 | 407 | return this->did > 0; |
e881ee23 AS |
408 | } |
409 | ||
410 | METHOD(attest_db_t, set_file, bool, | |
f4159ff8 | 411 | private_attest_db_t *this, char *file, bool create) |
e881ee23 | 412 | { |
1f179c63 | 413 | int fid; |
e881ee23 AS |
414 | enumerator_t *e; |
415 | ||
1f179c63 | 416 | if (this->file) |
e881ee23 AS |
417 | { |
418 | printf("file has already been set\n"); | |
419 | return FALSE; | |
420 | } | |
421 | this->file = strdup(file); | |
422 | ||
1f179c63 AS |
423 | if (!this->did) |
424 | { | |
425 | return TRUE; | |
426 | } | |
1f179c63 AS |
427 | e = this->db->query(this->db, "SELECT id FROM files " |
428 | "WHERE dir = ? AND name = ?", | |
429 | DB_INT, this->did, DB_TEXT, file, DB_INT); | |
e881ee23 AS |
430 | if (e) |
431 | { | |
1f179c63 | 432 | if (e->enumerate(e, &fid)) |
e881ee23 | 433 | { |
1f179c63 | 434 | this->fid = fid; |
e881ee23 | 435 | } |
e881ee23 AS |
436 | e->destroy(e); |
437 | } | |
1f179c63 | 438 | if (this->fid) |
f4159ff8 AS |
439 | { |
440 | return TRUE; | |
441 | } | |
442 | ||
443 | if (!create) | |
444 | { | |
0731d41c MW |
445 | printf("file '%s%s%s' not found in database\n", |
446 | this->dir, get_separator(this->dir), file); | |
2b28a131 | 447 | return FALSE; |
f4159ff8 AS |
448 | } |
449 | ||
450 | /* Add a new database entry */ | |
1f179c63 AS |
451 | if (1 == this->db->execute(this->db, &fid, |
452 | "INSERT INTO files (dir, name) VALUES (?, ?)", | |
453 | DB_INT, this->did, DB_TEXT, file)) | |
454 | { | |
455 | this->fid = fid; | |
456 | } | |
0731d41c MW |
457 | printf("file '%s%s%s' %sinserted into database\n", this->dir, |
458 | get_separator(this->dir), file, this->fid ? "" : "could not be "); | |
f4159ff8 | 459 | |
1f179c63 | 460 | return this->fid > 0; |
e881ee23 AS |
461 | } |
462 | ||
463 | METHOD(attest_db_t, set_fid, bool, | |
464 | private_attest_db_t *this, int fid) | |
465 | { | |
466 | enumerator_t *e; | |
1f179c63 | 467 | int did; |
e881ee23 AS |
468 | char *file; |
469 | ||
1f179c63 | 470 | if (this->fid) |
e881ee23 AS |
471 | { |
472 | printf("file has already been set\n"); | |
473 | return FALSE; | |
474 | } | |
e881ee23 | 475 | |
1f179c63 AS |
476 | e = this->db->query(this->db, "SELECT dir, name FROM files WHERE id = ?", |
477 | DB_UINT, fid, DB_INT, DB_TEXT); | |
e881ee23 AS |
478 | if (e) |
479 | { | |
1f179c63 | 480 | if (e->enumerate(e, &did, &file)) |
e881ee23 | 481 | { |
1f179c63 AS |
482 | if (did) |
483 | { | |
484 | set_did(this, did); | |
485 | } | |
e881ee23 | 486 | this->file = strdup(file); |
1f179c63 | 487 | this->fid = fid; |
e881ee23 AS |
488 | } |
489 | else | |
490 | { | |
491 | printf("no file found with fid %d\n", fid); | |
492 | } | |
493 | e->destroy(e); | |
494 | } | |
1f179c63 | 495 | return this->fid > 0; |
e881ee23 AS |
496 | } |
497 | ||
37a73b9c AS |
498 | METHOD(attest_db_t, set_meas_directory, bool, |
499 | private_attest_db_t *this, char *dir) | |
500 | { | |
501 | size_t len; | |
502 | ||
503 | /* remove trailing '/' character if not root directory */ | |
504 | len = strlen(dir); | |
505 | if (len > 1 && dir[len-1] == '/') | |
506 | { | |
507 | dir[len-1] = '\0'; | |
508 | } | |
509 | this->meas_dir = strdup(dir); | |
510 | ||
511 | return TRUE; | |
512 | } | |
513 | ||
f2a521e7 | 514 | METHOD(attest_db_t, set_key, bool, |
cb4da3f6 | 515 | private_attest_db_t *this, chunk_t key, bool create) |
e881ee23 AS |
516 | { |
517 | enumerator_t *e; | |
f2a521e7 | 518 | char *owner; |
e881ee23 | 519 | |
f2a521e7 | 520 | if (this->key_set) |
e881ee23 | 521 | { |
f2a521e7 | 522 | printf("key has already been set\n"); |
e881ee23 AS |
523 | return FALSE; |
524 | } | |
cb4da3f6 | 525 | this->key = key; |
e881ee23 | 526 | |
f2a521e7 AS |
527 | e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?", |
528 | DB_BLOB, this->key, DB_INT, DB_TEXT); | |
e881ee23 AS |
529 | if (e) |
530 | { | |
f2a521e7 | 531 | if (e->enumerate(e, &this->kid, &owner)) |
e881ee23 | 532 | { |
cb4da3f6 | 533 | free(this->owner); |
f2a521e7 AS |
534 | this->owner = strdup(owner); |
535 | this->key_set = TRUE; | |
e881ee23 | 536 | } |
e881ee23 AS |
537 | e->destroy(e); |
538 | } | |
f2a521e7 | 539 | if (this->key_set) |
f4159ff8 AS |
540 | { |
541 | return TRUE; | |
542 | } | |
543 | ||
544 | if (!create) | |
545 | { | |
f2a521e7 | 546 | printf("key '%#B' not found in database\n", &this->key); |
2b28a131 | 547 | return FALSE; |
f4159ff8 AS |
548 | } |
549 | ||
550 | /* Add a new database entry */ | |
f2a521e7 AS |
551 | if (!this->owner) |
552 | { | |
553 | this->owner = strdup(""); | |
554 | } | |
555 | this->key_set = this->db->execute(this->db, &this->kid, | |
556 | "INSERT INTO keys (keyid, owner) VALUES (?, ?)", | |
557 | DB_BLOB, this->key, DB_TEXT, this->owner) == 1; | |
f4159ff8 | 558 | |
f2a521e7 AS |
559 | printf("key '%#B' %sinserted into database\n", &this->key, |
560 | this->key_set ? "" : "could not be "); | |
f4159ff8 | 561 | |
f2a521e7 | 562 | return this->key_set; |
e881ee23 | 563 | |
f2a521e7 AS |
564 | }; |
565 | ||
566 | METHOD(attest_db_t, set_kid, bool, | |
567 | private_attest_db_t *this, int kid) | |
e881ee23 AS |
568 | { |
569 | enumerator_t *e; | |
f2a521e7 AS |
570 | chunk_t key; |
571 | char *owner; | |
e881ee23 | 572 | |
f2a521e7 | 573 | if (this->key_set) |
e881ee23 | 574 | { |
f2a521e7 | 575 | printf("key has already been set\n"); |
e881ee23 AS |
576 | return FALSE; |
577 | } | |
f2a521e7 | 578 | this->kid = kid; |
e881ee23 | 579 | |
f2a521e7 | 580 | e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?", |
e0c66beb | 581 | DB_UINT, kid, DB_BLOB, DB_TEXT); |
e881ee23 AS |
582 | if (e) |
583 | { | |
f2a521e7 | 584 | if (e->enumerate(e, &key, &owner)) |
e881ee23 | 585 | { |
f2a521e7 AS |
586 | this->owner = strdup(owner); |
587 | this->key = chunk_clone(key); | |
588 | this->key_set = TRUE; | |
e881ee23 AS |
589 | } |
590 | else | |
591 | { | |
f2a521e7 | 592 | printf("no key found with kid %d\n", kid); |
e881ee23 AS |
593 | } |
594 | e->destroy(e); | |
595 | } | |
f2a521e7 | 596 | return this->key_set; |
e881ee23 | 597 | |
f2a521e7 AS |
598 | }; |
599 | ||
600 | METHOD(attest_db_t, set_product, bool, | |
601 | private_attest_db_t *this, char *product, bool create) | |
d37abe0f AS |
602 | { |
603 | enumerator_t *e; | |
d37abe0f | 604 | |
f2a521e7 | 605 | if (this->product_set) |
d37abe0f | 606 | { |
f2a521e7 | 607 | printf("product has already been set\n"); |
d37abe0f AS |
608 | return FALSE; |
609 | } | |
f2a521e7 | 610 | this->product = strdup(product); |
d37abe0f | 611 | |
f2a521e7 AS |
612 | e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?", |
613 | DB_TEXT, product, DB_INT); | |
d37abe0f AS |
614 | if (e) |
615 | { | |
f2a521e7 | 616 | if (e->enumerate(e, &this->pid)) |
d37abe0f | 617 | { |
f2a521e7 | 618 | this->product_set = TRUE; |
d37abe0f AS |
619 | } |
620 | e->destroy(e); | |
621 | } | |
f2a521e7 | 622 | if (this->product_set) |
d37abe0f AS |
623 | { |
624 | return TRUE; | |
625 | } | |
626 | ||
627 | if (!create) | |
628 | { | |
f2a521e7 | 629 | printf("product '%s' not found in database\n", product); |
d37abe0f AS |
630 | return FALSE; |
631 | } | |
632 | ||
633 | /* Add a new database entry */ | |
f2a521e7 AS |
634 | this->product_set = this->db->execute(this->db, &this->pid, |
635 | "INSERT INTO products (name) VALUES (?)", | |
636 | DB_TEXT, product) == 1; | |
d37abe0f | 637 | |
f2a521e7 AS |
638 | printf("product '%s' %sinserted into database\n", product, |
639 | this->product_set ? "" : "could not be "); | |
640 | ||
641 | return this->product_set; | |
d37abe0f AS |
642 | } |
643 | ||
f2a521e7 AS |
644 | METHOD(attest_db_t, set_pid, bool, |
645 | private_attest_db_t *this, int pid) | |
d37abe0f AS |
646 | { |
647 | enumerator_t *e; | |
f2a521e7 | 648 | char *product; |
d37abe0f | 649 | |
f2a521e7 | 650 | if (this->product_set) |
d37abe0f | 651 | { |
f2a521e7 | 652 | printf("product has already been set\n"); |
d37abe0f AS |
653 | return FALSE; |
654 | } | |
f2a521e7 | 655 | this->pid = pid; |
d37abe0f | 656 | |
f2a521e7 | 657 | e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?", |
e0c66beb | 658 | DB_UINT, pid, DB_TEXT); |
d37abe0f AS |
659 | if (e) |
660 | { | |
f2a521e7 | 661 | if (e->enumerate(e, &product)) |
d37abe0f | 662 | { |
f2a521e7 AS |
663 | this->product = strdup(product); |
664 | this->product_set = TRUE; | |
d37abe0f AS |
665 | } |
666 | else | |
667 | { | |
f2a521e7 | 668 | printf("no product found with pid %d in database\n", pid); |
d37abe0f AS |
669 | } |
670 | e->destroy(e); | |
671 | } | |
f2a521e7 | 672 | return this->product_set; |
d37abe0f AS |
673 | } |
674 | ||
1bb6a086 AS |
675 | METHOD(attest_db_t, set_package, bool, |
676 | private_attest_db_t *this, char *package, bool create) | |
677 | { | |
678 | enumerator_t *e; | |
679 | ||
680 | if (this->package_set) | |
681 | { | |
682 | printf("package has already been set\n"); | |
683 | return FALSE; | |
684 | } | |
685 | this->package = strdup(package); | |
686 | ||
687 | e = this->db->query(this->db, "SELECT id FROM packages WHERE name = ?", | |
688 | DB_TEXT, package, DB_INT); | |
689 | if (e) | |
690 | { | |
691 | if (e->enumerate(e, &this->gid)) | |
692 | { | |
693 | this->package_set = TRUE; | |
694 | } | |
695 | e->destroy(e); | |
696 | } | |
697 | if (this->package_set) | |
698 | { | |
699 | return TRUE; | |
700 | } | |
701 | ||
702 | if (!create) | |
703 | { | |
704 | printf("package '%s' not found in database\n", package); | |
705 | return FALSE; | |
706 | } | |
707 | ||
708 | /* Add a new database entry */ | |
709 | this->package_set = this->db->execute(this->db, &this->gid, | |
710 | "INSERT INTO packages (name) VALUES (?)", | |
711 | DB_TEXT, package) == 1; | |
712 | ||
713 | printf("package '%s' %sinserted into database\n", package, | |
714 | this->package_set ? "" : "could not be "); | |
715 | ||
716 | return this->package_set; | |
717 | } | |
718 | ||
719 | METHOD(attest_db_t, set_gid, bool, | |
720 | private_attest_db_t *this, int gid) | |
721 | { | |
722 | enumerator_t *e; | |
723 | char *package; | |
724 | ||
725 | if (this->package_set) | |
726 | { | |
727 | printf("package has already been set\n"); | |
728 | return FALSE; | |
729 | } | |
730 | this->gid = gid; | |
731 | ||
732 | e = this->db->query(this->db, "SELECT name FROM packages WHERE id = ?", | |
733 | DB_UINT, gid, DB_TEXT); | |
734 | if (e) | |
735 | { | |
736 | if (e->enumerate(e, &package)) | |
737 | { | |
738 | this->package = strdup(package); | |
739 | this->package_set = TRUE; | |
740 | } | |
741 | else | |
742 | { | |
743 | printf("no package found with gid %d in database\n", gid); | |
744 | } | |
745 | e->destroy(e); | |
746 | } | |
747 | return this->package_set; | |
748 | } | |
749 | ||
750 | METHOD(attest_db_t, set_version, bool, | |
751 | private_attest_db_t *this, char *version) | |
752 | { | |
753 | if (this->version_set) | |
754 | { | |
755 | printf("version has already been set\n"); | |
756 | return FALSE; | |
757 | } | |
758 | this->version = strdup(version); | |
759 | this->version_set = TRUE; | |
760 | ||
761 | return TRUE; | |
762 | } | |
763 | ||
764 | ||
e881ee23 AS |
765 | METHOD(attest_db_t, set_algo, void, |
766 | private_attest_db_t *this, pts_meas_algorithms_t algo) | |
767 | { | |
768 | this->algo = algo; | |
769 | } | |
770 | ||
0f236aac AS |
771 | METHOD(attest_db_t, set_relative, void, |
772 | private_attest_db_t *this) | |
773 | { | |
774 | this->relative = TRUE; | |
775 | } | |
776 | ||
71c7b435 AS |
777 | METHOD(attest_db_t, set_package_state, void, |
778 | private_attest_db_t *this, os_package_state_t package_state) | |
1bb6a086 | 779 | { |
71c7b435 | 780 | this->package_state = package_state; |
1bb6a086 AS |
781 | } |
782 | ||
e0c66beb AS |
783 | METHOD(attest_db_t, set_sequence, void, |
784 | private_attest_db_t *this, int seq_no) | |
785 | { | |
786 | this->seq_no = seq_no; | |
787 | } | |
788 | ||
f2a521e7 AS |
789 | METHOD(attest_db_t, set_owner, void, |
790 | private_attest_db_t *this, char *owner) | |
791 | { | |
792 | free(this->owner); | |
793 | this->owner = strdup(owner); | |
794 | } | |
795 | ||
81ee269d AS |
796 | METHOD(attest_db_t, set_utc, void, |
797 | private_attest_db_t *this) | |
798 | { | |
799 | this->utc = TRUE; | |
800 | } | |
801 | ||
6b55276a AS |
802 | METHOD(attest_db_t, list_components, void, |
803 | private_attest_db_t *this) | |
804 | { | |
805 | enumerator_t *e; | |
6b55276a | 806 | pts_comp_func_name_t *cfn; |
e0c66beb | 807 | int seq_no, cid, vid, name, qualifier, count = 0; |
6b55276a | 808 | |
f2a521e7 | 809 | if (this->kid) |
6b55276a AS |
810 | { |
811 | e = this->db->query(this->db, | |
e0c66beb | 812 | "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier " |
6b55276a | 813 | "FROM components AS c " |
f2a521e7 | 814 | "JOIN key_component AS kc ON c.id = kc.component " |
e0c66beb AS |
815 | "WHERE kc.key = ? ORDER BY kc.seq_no", |
816 | DB_UINT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT); | |
817 | if (e) | |
818 | { | |
819 | while (e->enumerate(e, &cid, &seq_no, &vid, &name, &qualifier)) | |
820 | { | |
821 | cfn = pts_comp_func_name_create(vid, name, qualifier); | |
822 | printf("%4d: #%-2d %s\n", seq_no, cid, print_cfn(cfn)); | |
823 | cfn->destroy(cfn); | |
824 | count++; | |
825 | } | |
826 | e->destroy(e); | |
827 | printf("%d component%s found for key %#B\n", count, | |
828 | (count == 1) ? "" : "s", &this->key); | |
829 | } | |
6b55276a AS |
830 | } |
831 | else | |
832 | { | |
833 | e = this->db->query(this->db, | |
834 | "SELECT id, vendor_id, name, qualifier FROM components " | |
835 | "ORDER BY vendor_id, name, qualifier", | |
836 | DB_INT, DB_INT, DB_INT, DB_INT); | |
e0c66beb | 837 | if (e) |
6b55276a | 838 | { |
e0c66beb AS |
839 | while (e->enumerate(e, &cid, &vid, &name, &qualifier)) |
840 | { | |
841 | cfn = pts_comp_func_name_create(vid, name, qualifier); | |
842 | printf("%4d: %s\n", cid, print_cfn(cfn)); | |
843 | cfn->destroy(cfn); | |
844 | count++; | |
845 | } | |
846 | e->destroy(e); | |
847 | printf("%d component%s found\n", count, (count == 1) ? "" : "s"); | |
6b55276a | 848 | } |
6b55276a AS |
849 | } |
850 | } | |
851 | ||
ac6dd7d4 AS |
852 | METHOD(attest_db_t, list_devices, void, |
853 | private_attest_db_t *this) | |
854 | { | |
c88104aa | 855 | enumerator_t *e, *e_ar; |
72631301 | 856 | chunk_t ar_id_value = chunk_empty; |
20f90d71 | 857 | char *product, *device, *description; |
7b6cc33e | 858 | time_t timestamp; |
20f90d71 | 859 | int id, last_id = 0, ar_id = 0, last_ar_id = 0, device_count = 0, trusted; |
29645621 | 860 | int session_id, rec; |
b12c53ce | 861 | uint32_t ar_id_type; |
29645621 | 862 | u_int tstamp; |
ac6dd7d4 AS |
863 | |
864 | e = this->db->query(this->db, | |
20f90d71 AS |
865 | "SELECT d.id, d.value, d.trusted, d.description, " |
866 | "s.id, s.time, s.identity, s.rec, p.name " | |
b8db66de AS |
867 | "FROM devices AS d " |
868 | "JOIN sessions AS s ON d.id = s.device " | |
869 | "JOIN products AS p ON p.id = s.product " | |
20f90d71 AS |
870 | "ORDER BY d.value, s.time DESC", DB_INT, DB_TEXT, DB_INT, DB_TEXT, |
871 | DB_INT, DB_UINT, DB_INT, DB_INT, DB_TEXT); | |
7b6cc33e | 872 | |
ac6dd7d4 AS |
873 | if (e) |
874 | { | |
20f90d71 AS |
875 | while (e->enumerate(e, &id, &device, &trusted, &description, |
876 | &session_id, &tstamp, &ar_id, &rec, &product)) | |
ac6dd7d4 | 877 | { |
7b6cc33e AS |
878 | if (id != last_id) |
879 | { | |
20f90d71 AS |
880 | printf("%4d: %s %s - %s - %s\n", id, trusted ? "+" : "-", |
881 | device, product, description); | |
7b6cc33e AS |
882 | device_count++; |
883 | last_id = id; | |
884 | } | |
2b61f7ba | 885 | timestamp = tstamp; |
19ce03be | 886 | printf("%4d: %T", session_id, ×tamp, this->utc); |
a1bc67d6 | 887 | if (ar_id) |
c88104aa | 888 | { |
a1bc67d6 | 889 | if (ar_id != last_ar_id) |
c88104aa | 890 | { |
a1bc67d6 | 891 | chunk_free(&ar_id_value); |
c88104aa | 892 | e_ar = this->db->query(this->db, |
b8db66de | 893 | "SELECT type, value FROM identities " |
a1bc67d6 AS |
894 | "WHERE id = ?", DB_INT, ar_id, DB_INT, DB_BLOB); |
895 | if (e_ar) | |
c88104aa | 896 | { |
a1bc67d6 | 897 | e_ar->enumerate(e_ar, &ar_id_type, &ar_id_value); |
6c998b8b | 898 | ar_id_value = chunk_clone(ar_id_value); |
a1bc67d6 | 899 | e_ar->destroy(e_ar); |
c88104aa | 900 | } |
c88104aa | 901 | } |
a1bc67d6 | 902 | if (ar_id_value.len) |
c88104aa | 903 | { |
f2e6a67e | 904 | printf(" %.*s", (int)ar_id_value.len, ar_id_value.ptr); |
c88104aa | 905 | } |
6c998b8b | 906 | last_ar_id = ar_id; |
c88104aa | 907 | } |
29645621 | 908 | printf(" - %N\n", TNC_IMV_Action_Recommendation_names, rec); |
ac6dd7d4 AS |
909 | } |
910 | e->destroy(e); | |
a1bc67d6 | 911 | free(ar_id_value.ptr); |
c88104aa | 912 | |
7b6cc33e AS |
913 | printf("%d device%s found\n", device_count, |
914 | (device_count == 1) ? "" : "s"); | |
ac6dd7d4 AS |
915 | } |
916 | } | |
917 | ||
f2a521e7 AS |
918 | METHOD(attest_db_t, list_keys, void, |
919 | private_attest_db_t *this) | |
920 | { | |
921 | enumerator_t *e; | |
922 | chunk_t keyid; | |
923 | char *owner; | |
924 | int kid, count = 0; | |
925 | ||
926 | if (this->cid) | |
927 | { | |
928 | e = this->db->query(this->db, | |
929 | "SELECT k.id, k.keyid, k.owner FROM keys AS k " | |
930 | "JOIN key_component AS kc ON k.id = kc.key " | |
931 | "WHERE kc.component = ? ORDER BY k.keyid", | |
e0c66beb | 932 | DB_UINT, this->cid, DB_INT, DB_BLOB, DB_TEXT); |
f2a521e7 AS |
933 | if (e) |
934 | { | |
935 | while (e->enumerate(e, &kid, &keyid, &owner)) | |
936 | { | |
0f236aac | 937 | printf("%4d: %#B '%s'\n", kid, &keyid, owner); |
f2a521e7 AS |
938 | count++; |
939 | } | |
940 | e->destroy(e); | |
941 | } | |
942 | } | |
943 | else | |
944 | { | |
945 | e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys " | |
946 | "ORDER BY keyid", | |
947 | DB_INT, DB_BLOB, DB_TEXT); | |
948 | if (e) | |
949 | { | |
950 | while (e->enumerate(e, &kid, &keyid, &owner)) | |
951 | { | |
0f236aac | 952 | printf("%4d: %#B '%s'\n", kid, &keyid, owner); |
f2a521e7 AS |
953 | count++; |
954 | } | |
955 | e->destroy(e); | |
956 | } | |
957 | } | |
958 | ||
959 | printf("%d key%s found", count, (count == 1) ? "" : "s"); | |
960 | if (this->comp_set) | |
961 | { | |
962 | printf(" for component '%s'", print_cfn(this->cfn)); | |
963 | } | |
964 | printf("\n"); | |
965 | } | |
966 | ||
e881ee23 AS |
967 | METHOD(attest_db_t, list_files, void, |
968 | private_attest_db_t *this) | |
969 | { | |
970 | enumerator_t *e; | |
1f179c63 AS |
971 | char *dir, *file; |
972 | int did, last_did = 0, fid, count = 0; | |
e881ee23 | 973 | |
1f179c63 | 974 | if (this->did) |
e881ee23 AS |
975 | { |
976 | e = this->db->query(this->db, | |
1f179c63 AS |
977 | "SELECT id, name FROM files WHERE dir = ? ORDER BY name", |
978 | DB_INT, this->did, DB_INT, DB_TEXT); | |
dac97629 AS |
979 | if (e) |
980 | { | |
1f179c63 | 981 | while (e->enumerate(e, &fid, &file)) |
dac97629 | 982 | { |
60da0153 | 983 | printf("%6d: %s\n", fid, file); |
dac97629 AS |
984 | count++; |
985 | } | |
986 | e->destroy(e); | |
987 | } | |
1f179c63 AS |
988 | printf("%d file%s found in directory '%s'\n", count, |
989 | (count == 1) ? "" : "s", this->dir); | |
e881ee23 AS |
990 | } |
991 | else | |
992 | { | |
993 | e = this->db->query(this->db, | |
1f179c63 AS |
994 | "SELECT d.id, d.path, f.id, f.name FROM files AS f " |
995 | "JOIN directories AS d ON f.dir = d.id " | |
996 | "ORDER BY d.path, f.name", | |
997 | DB_INT, DB_TEXT, DB_INT, DB_TEXT); | |
dac97629 | 998 | if (e) |
e881ee23 | 999 | { |
1f179c63 | 1000 | while (e->enumerate(e, &did, &dir, &fid, &file)) |
dac97629 | 1001 | { |
1f179c63 AS |
1002 | if (did != last_did) |
1003 | { | |
60da0153 | 1004 | printf("%6d: %s\n", did, dir); |
1f179c63 AS |
1005 | last_did = did; |
1006 | } | |
60da0153 | 1007 | printf("%6d: %s\n", fid, file); |
dac97629 AS |
1008 | count++; |
1009 | } | |
1010 | e->destroy(e); | |
e881ee23 | 1011 | } |
1f179c63 | 1012 | printf("%d file%s found\n", count, (count == 1) ? "" : "s"); |
dac97629 | 1013 | } |
1f179c63 | 1014 | } |
e881ee23 | 1015 | |
1f179c63 AS |
1016 | METHOD(attest_db_t, list_directories, void, |
1017 | private_attest_db_t *this) | |
1018 | { | |
1019 | enumerator_t *e; | |
1020 | char *dir; | |
1021 | int did, count = 0; | |
1022 | ||
1023 | if (this->file) | |
dac97629 | 1024 | { |
1f179c63 AS |
1025 | e = this->db->query(this->db, |
1026 | "SELECT d.id, d.path FROM directories AS d " | |
1027 | "JOIN files AS f ON f.dir = d.id WHERE f.name = ? " | |
1028 | "ORDER BY path", DB_TEXT, this->file, DB_INT, DB_TEXT); | |
1029 | if (e) | |
1030 | { | |
1031 | while (e->enumerate(e, &did, &dir)) | |
1032 | { | |
1033 | printf("%4d: %s\n", did, dir); | |
1034 | count++; | |
1035 | } | |
1036 | e->destroy(e); | |
1037 | } | |
1038 | printf("%d director%s found containing file '%s'\n", count, | |
1039 | (count == 1) ? "y" : "ies", this->file); | |
1040 | } | |
1041 | else | |
1042 | { | |
1043 | e = this->db->query(this->db, | |
1044 | "SELECT id, path FROM directories ORDER BY path", | |
1045 | DB_INT, DB_TEXT); | |
1046 | if (e) | |
1047 | { | |
1048 | while (e->enumerate(e, &did, &dir)) | |
1049 | { | |
1050 | printf("%4d: %s\n", did, dir); | |
1051 | count++; | |
1052 | } | |
1053 | e->destroy(e); | |
1054 | } | |
1055 | printf("%d director%s found\n", count, (count == 1) ? "y" : "ies"); | |
e881ee23 AS |
1056 | } |
1057 | } | |
1058 | ||
1bb6a086 AS |
1059 | METHOD(attest_db_t, list_packages, void, |
1060 | private_attest_db_t *this) | |
1061 | { | |
1062 | enumerator_t *e; | |
1063 | char *package, *version; | |
71c7b435 AS |
1064 | os_package_state_t package_state; |
1065 | int blacklist, security, gid, gid_old = 0, spaces, count = 0, t; | |
9fab0a58 | 1066 | time_t timestamp; |
1bb6a086 AS |
1067 | |
1068 | if (this->pid) | |
1069 | { | |
1070 | e = this->db->query(this->db, | |
71c7b435 AS |
1071 | "SELECT p.id, p.name, " |
1072 | "v.release, v.security, v.blacklist, v.time " | |
d598f2db AS |
1073 | "FROM packages AS p JOIN versions AS v ON v.package = p.id " |
1074 | "WHERE v.product = ? ORDER BY p.name, v.release", | |
71c7b435 AS |
1075 | DB_INT, this->pid, |
1076 | DB_INT, DB_TEXT, DB_TEXT, DB_INT, DB_INT, DB_INT); | |
1bb6a086 AS |
1077 | if (e) |
1078 | { | |
71c7b435 AS |
1079 | while (e->enumerate(e, &gid, &package, |
1080 | &version, &security, &blacklist, &t)) | |
1bb6a086 AS |
1081 | { |
1082 | if (gid != gid_old) | |
1083 | { | |
90741863 | 1084 | printf("%5d: %s,", gid, package); |
1bb6a086 AS |
1085 | gid_old = gid; |
1086 | } | |
1087 | else | |
1088 | { | |
90741863 | 1089 | spaces = 8 + strlen(package); |
1bb6a086 AS |
1090 | while (spaces--) |
1091 | { | |
1092 | printf(" "); | |
1093 | } | |
1094 | } | |
9fab0a58 | 1095 | timestamp = t; |
71c7b435 AS |
1096 | if (blacklist) |
1097 | { | |
1098 | package_state = OS_PACKAGE_STATE_BLACKLIST; | |
1099 | } | |
1100 | else | |
1101 | { | |
1102 | package_state = security ? OS_PACKAGE_STATE_SECURITY : | |
1103 | OS_PACKAGE_STATE_UPDATE; | |
1104 | } | |
9fab0a58 | 1105 | printf(" %T (%s)%N\n", ×tamp, this->utc, version, |
71c7b435 | 1106 | os_package_state_names, package_state); |
1bb6a086 AS |
1107 | count++; |
1108 | } | |
1109 | e->destroy(e); | |
1110 | } | |
1111 | } | |
1112 | else | |
1113 | { | |
1114 | e = this->db->query(this->db, "SELECT id, name FROM packages " | |
1115 | "ORDER BY name", | |
1116 | DB_INT, DB_TEXT); | |
1117 | if (e) | |
1118 | { | |
1119 | while (e->enumerate(e, &gid, &package)) | |
1120 | { | |
1121 | printf("%4d: %s\n", gid, package); | |
1122 | count++; | |
1123 | } | |
1124 | e->destroy(e); | |
1125 | } | |
1126 | } | |
1127 | ||
1128 | printf("%d package%s found", count, (count == 1) ? "" : "s"); | |
1129 | if (this->product_set) | |
1130 | { | |
1131 | printf(" for product '%s'", this->product); | |
1132 | } | |
1133 | printf("\n"); | |
1134 | } | |
1135 | ||
e881ee23 AS |
1136 | METHOD(attest_db_t, list_products, void, |
1137 | private_attest_db_t *this) | |
1138 | { | |
1139 | enumerator_t *e; | |
1140 | char *product; | |
dac97629 | 1141 | int pid, meas, meta, count = 0; |
e881ee23 AS |
1142 | |
1143 | if (this->fid) | |
1144 | { | |
1145 | e = this->db->query(this->db, | |
dac97629 AS |
1146 | "SELECT p.id, p.name, pf.measurement, pf.metadata " |
1147 | "FROM products AS p " | |
e881ee23 | 1148 | "JOIN product_file AS pf ON p.id = pf.product " |
0ee1fe15 | 1149 | "WHERE pf.file = ? ORDER BY p.name", |
e0c66beb | 1150 | DB_UINT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT); |
dac97629 AS |
1151 | if (e) |
1152 | { | |
1153 | while (e->enumerate(e, &pid, &product, &meas, &meta)) | |
1154 | { | |
0f236aac | 1155 | printf("%4d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", |
dac97629 AS |
1156 | product); |
1157 | count++; | |
1158 | } | |
1159 | e->destroy(e); | |
1160 | } | |
e881ee23 AS |
1161 | } |
1162 | else | |
1163 | { | |
1164 | e = this->db->query(this->db, "SELECT id, name FROM products " | |
1165 | "ORDER BY name", | |
1166 | DB_INT, DB_TEXT); | |
dac97629 | 1167 | if (e) |
e881ee23 | 1168 | { |
dac97629 AS |
1169 | while (e->enumerate(e, &pid, &product)) |
1170 | { | |
0f236aac | 1171 | printf("%4d: %s\n", pid, product); |
dac97629 AS |
1172 | count++; |
1173 | } | |
1174 | e->destroy(e); | |
e881ee23 | 1175 | } |
dac97629 | 1176 | } |
e881ee23 | 1177 | |
dac97629 | 1178 | printf("%d product%s found", count, (count == 1) ? "" : "s"); |
1f179c63 | 1179 | if (this->fid) |
dac97629 AS |
1180 | { |
1181 | printf(" for file '%s'", this->file); | |
e881ee23 | 1182 | } |
dac97629 | 1183 | printf("\n"); |
e881ee23 AS |
1184 | } |
1185 | ||
b8db66de AS |
1186 | METHOD(attest_db_t, list_hashes, void, |
1187 | private_attest_db_t *this) | |
e881ee23 AS |
1188 | { |
1189 | enumerator_t *e; | |
60da0153 | 1190 | char *file, *dir, *product, *hash; |
b8db66de | 1191 | int id, fid, fid_old = 0, did, did_old = 0, pid, pid_old = 0, count = 0; |
e881ee23 | 1192 | |
b8db66de | 1193 | if (this->pid && this->fid && this->did) |
e881ee23 | 1194 | { |
60da0153 AS |
1195 | printf("%6d: %s\n", this->did, this->dir); |
1196 | printf("%6d: %s\n", this->fid, this->file); | |
e881ee23 | 1197 | e = this->db->query(this->db, |
60da0153 AS |
1198 | "SELECT h.id, h.hash FROM file_hashes AS h " |
1199 | "JOIN versions AS v ON h.version = v.id " | |
1200 | "WHERE h.algo = ? AND h.file = ? AND v.product = ?", | |
b8db66de | 1201 | DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->pid, |
60da0153 | 1202 | DB_INT, DB_TEXT); |
e881ee23 AS |
1203 | if (e) |
1204 | { | |
b8db66de | 1205 | while (e->enumerate(e, &id, &hash)) |
e881ee23 | 1206 | { |
60da0153 | 1207 | printf("%6d: %s\n", id, hash); |
b8db66de | 1208 | count++; |
e881ee23 AS |
1209 | } |
1210 | e->destroy(e); | |
b8db66de AS |
1211 | |
1212 | printf("%d %N value%s found for product '%s'\n", count, | |
1213 | pts_meas_algorithm_names, this->algo, | |
1214 | (count == 1) ? "" : "s", this->product); | |
e881ee23 AS |
1215 | } |
1216 | } | |
b8db66de | 1217 | else if (this->pid && this->file) |
645f55eb AS |
1218 | { |
1219 | e = this->db->query(this->db, | |
b8db66de AS |
1220 | "SELECT h.id, h.hash, f.id, d.id, d.path " |
1221 | "FROM file_hashes AS h " | |
1222 | "JOIN files AS f ON h.file = f.id " | |
1223 | "JOIN directories AS d ON f.dir = d.id " | |
60da0153 AS |
1224 | "JOIN versions AS v ON h.version = v.id " |
1225 | "WHERE h.algo = ? AND v.product = ? AND f.name = ? " | |
b8db66de AS |
1226 | "ORDER BY d.path, f.name, h.hash", |
1227 | DB_INT, this->algo, DB_INT, this->pid, DB_TEXT, this->file, | |
60da0153 | 1228 | DB_INT, DB_TEXT, DB_INT, DB_INT, DB_TEXT); |
645f55eb AS |
1229 | if (e) |
1230 | { | |
b8db66de | 1231 | while (e->enumerate(e, &id, &hash, &fid, &did, &dir)) |
645f55eb | 1232 | { |
b8db66de | 1233 | if (did != did_old) |
645f55eb | 1234 | { |
60da0153 | 1235 | printf("%6d: %s\n", did, dir); |
b8db66de AS |
1236 | did_old = did; |
1237 | } | |
1238 | if (fid != fid_old) | |
1239 | { | |
60da0153 | 1240 | printf("%6d: %s\n", fid, this->file); |
b8db66de | 1241 | fid_old = fid; |
645f55eb | 1242 | } |
60da0153 | 1243 | printf("%6d: %s\n", id, hash); |
645f55eb AS |
1244 | count++; |
1245 | } | |
1246 | e->destroy(e); | |
1247 | ||
1248 | printf("%d %N value%s found for product '%s'\n", count, | |
358dbe48 | 1249 | pts_meas_algorithm_names, this->algo, |
645f55eb AS |
1250 | (count == 1) ? "" : "s", this->product); |
1251 | } | |
1252 | } | |
b8db66de | 1253 | else if (this->pid && this->did) |
f4263eae | 1254 | { |
60da0153 | 1255 | printf("%6d: %s\n", this->did, this->dir); |
f4263eae | 1256 | e = this->db->query(this->db, |
b8db66de AS |
1257 | "SELECT h.id, h.hash, f.id, f.name " |
1258 | "FROM file_hashes AS h " | |
1259 | "JOIN files AS f ON h.file = f.id " | |
60da0153 AS |
1260 | "JOIN versions AS v ON h.version = v.id " |
1261 | "WHERE h.algo = ? AND v.product = ? AND f.dir = ? " | |
b8db66de AS |
1262 | "ORDER BY f.name, h.hash", |
1263 | DB_INT, this->algo, DB_INT, this->pid, DB_INT, this->did, | |
60da0153 | 1264 | DB_INT, DB_TEXT, DB_INT, DB_TEXT); |
f4263eae AS |
1265 | if (e) |
1266 | { | |
b8db66de | 1267 | while (e->enumerate(e, &id, &hash, &fid, &file)) |
f4263eae | 1268 | { |
b8db66de AS |
1269 | if (fid != fid_old) |
1270 | { | |
60da0153 | 1271 | printf("%6d: %s\n", fid, file); |
b8db66de AS |
1272 | fid_old = fid; |
1273 | } | |
60da0153 | 1274 | printf("%6d: %s\n", id, hash); |
f4263eae AS |
1275 | count++; |
1276 | } | |
1277 | e->destroy(e); | |
1278 | ||
1279 | printf("%d %N value%s found for product '%s'\n", count, | |
1280 | pts_meas_algorithm_names, this->algo, | |
1281 | (count == 1) ? "" : "s", this->product); | |
f4263eae AS |
1282 | } |
1283 | } | |
645f55eb | 1284 | else if (this->pid) |
e881ee23 AS |
1285 | { |
1286 | e = this->db->query(this->db, | |
b8db66de AS |
1287 | "SELECT h.id, h.hash, f.id, f.name, d.id, d.path " |
1288 | "FROM file_hashes AS h " | |
1289 | "JOIN files AS f ON h.file = f.id " | |
1290 | "JOIN directories AS d ON f.dir = d.id " | |
60da0153 AS |
1291 | "JOIN versions AS v ON h.version = v.id " |
1292 | "WHERE h.algo = ? AND v.product = ? " | |
b8db66de AS |
1293 | "ORDER BY d.path, f.name, h.hash", |
1294 | DB_INT, this->algo, DB_INT, this->pid, | |
60da0153 | 1295 | DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_INT, DB_TEXT); |
e881ee23 AS |
1296 | if (e) |
1297 | { | |
b8db66de | 1298 | while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir)) |
e881ee23 | 1299 | { |
b8db66de | 1300 | if (did != did_old) |
e881ee23 | 1301 | { |
60da0153 | 1302 | printf("%6d: %s\n", did, dir); |
e881ee23 AS |
1303 | did_old = did; |
1304 | } | |
b8db66de AS |
1305 | if (fid != fid_old) |
1306 | { | |
60da0153 | 1307 | printf("%6d: %s\n", fid, file); |
b8db66de AS |
1308 | fid_old = fid; |
1309 | } | |
60da0153 | 1310 | printf("%6d: %s\n", id, hash); |
e881ee23 AS |
1311 | count++; |
1312 | } | |
1313 | e->destroy(e); | |
1314 | ||
1315 | printf("%d %N value%s found for product '%s'\n", count, | |
358dbe48 | 1316 | pts_meas_algorithm_names, this->algo, |
e881ee23 AS |
1317 | (count == 1) ? "" : "s", this->product); |
1318 | } | |
1319 | } | |
b8db66de | 1320 | else if (this->fid && this->did) |
e881ee23 AS |
1321 | { |
1322 | e = this->db->query(this->db, | |
b8db66de | 1323 | "SELECT h.id, h.hash, p.id, p.name FROM file_hashes AS h " |
60da0153 AS |
1324 | "JOIN versions AS v ON h.version = v.id " |
1325 | "JOIN products AS p ON v.product = p.id " | |
b8db66de AS |
1326 | "WHERE h.algo = ? AND h.file = ? " |
1327 | "ORDER BY p.name, h.hash", | |
1328 | DB_INT, this->algo, DB_INT, this->fid, | |
60da0153 | 1329 | DB_INT, DB_TEXT, DB_INT, DB_TEXT); |
e881ee23 AS |
1330 | if (e) |
1331 | { | |
b8db66de | 1332 | while (e->enumerate(e, &id, &hash, &pid, &product)) |
e881ee23 | 1333 | { |
b8db66de AS |
1334 | if (pid != pid_old) |
1335 | { | |
60da0153 | 1336 | printf("%6d: %s\n", pid, product); |
b8db66de AS |
1337 | pid_old = pid; |
1338 | } | |
60da0153 | 1339 | printf("%6d: %s\n", id, hash); |
e881ee23 AS |
1340 | count++; |
1341 | } | |
1342 | e->destroy(e); | |
1343 | ||
b8db66de AS |
1344 | printf("%d %N value%s found for file '%s%s%s'\n", count, |
1345 | pts_meas_algorithm_names, this->algo, | |
0ee1fe15 | 1346 | (count == 1) ? "" : "s", this->dir, |
0731d41c | 1347 | get_separator(this->dir), this->file); |
b8db66de AS |
1348 | } |
1349 | } | |
1350 | else if (this->file) | |
1351 | { | |
1352 | e = this->db->query(this->db, | |
1353 | "SELECT h.id, h.hash, f.id, d.id, d.path, p.id, p.name " | |
1354 | "FROM file_hashes AS h " | |
1355 | "JOIN files AS f ON h.file = f.id " | |
1356 | "JOIN directories AS d ON f.dir = d.id " | |
60da0153 AS |
1357 | "JOIN versions AS v ON h.version = v.id " |
1358 | "JOIN products AS p ON v.product = p.id " | |
b8db66de AS |
1359 | "WHERE h.algo = ? AND f.name = ? " |
1360 | "ORDER BY d.path, f.name, p.name, h.hash", | |
1361 | DB_INT, this->algo, DB_TEXT, this->file, | |
60da0153 | 1362 | DB_INT, DB_TEXT, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_TEXT); |
b8db66de AS |
1363 | if (e) |
1364 | { | |
1365 | while (e->enumerate(e, &id, &hash, &fid, &did, &dir, &pid, &product)) | |
1366 | { | |
1367 | if (did != did_old) | |
1368 | { | |
60da0153 | 1369 | printf("%6d: %s\n", did, dir); |
b8db66de AS |
1370 | did_old = did; |
1371 | } | |
1372 | if (fid != fid_old) | |
1373 | { | |
60da0153 | 1374 | printf("%6d: %s\n", fid, this->file); |
b8db66de AS |
1375 | fid_old = fid; |
1376 | pid_old = 0; | |
1377 | } | |
1378 | if (pid != pid_old) | |
1379 | { | |
60da0153 | 1380 | printf("%6d: %s\n", pid, product); |
b8db66de AS |
1381 | pid_old = pid; |
1382 | } | |
60da0153 | 1383 | printf("%6d: %s\n", id, hash); |
b8db66de AS |
1384 | count++; |
1385 | } | |
1386 | e->destroy(e); | |
1387 | ||
1388 | printf("%d %N value%s found\n", count, pts_meas_algorithm_names, | |
1389 | this->algo, (count == 1) ? "" : "s"); | |
1390 | } | |
1391 | ||
1392 | } | |
1393 | else if (this->did) | |
1394 | { | |
1395 | e = this->db->query(this->db, | |
1396 | "SELECT h.id, h.hash, f.id, f.name, p.id, p.name " | |
1397 | "FROM file_hashes AS h " | |
1398 | "JOIN files AS f ON h.file = f.id " | |
60da0153 AS |
1399 | "JOIN versions AS v ON h.version = v.id " |
1400 | "JOIN products AS p ON v.product = p.id " | |
b8db66de AS |
1401 | "WHERE h.algo = ? AND f.dir = ? " |
1402 | "ORDER BY f.name, p.name, h.hash", | |
1403 | DB_INT, this->algo, DB_INT, this->did, | |
60da0153 | 1404 | DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_INT, DB_TEXT); |
b8db66de AS |
1405 | if (e) |
1406 | { | |
1407 | while (e->enumerate(e, &id, &hash, &fid, &file, &pid, &product)) | |
1408 | { | |
1409 | if (fid != fid_old) | |
1410 | { | |
60da0153 | 1411 | printf("%6d: %s\n", fid, file); |
b8db66de AS |
1412 | fid_old = fid; |
1413 | pid_old = 0; | |
1414 | } | |
1415 | if (pid != pid_old) | |
1416 | { | |
60da0153 | 1417 | printf("%6d: %s\n", pid, product); |
b8db66de AS |
1418 | pid_old = pid; |
1419 | } | |
60da0153 | 1420 | printf("%6d: %s\n", id, hash); |
b8db66de AS |
1421 | count++; |
1422 | } | |
1423 | e->destroy(e); | |
1424 | ||
1425 | printf("%d %N value%s found for directory '%s'\n", count, | |
1426 | pts_meas_algorithm_names, this->algo, | |
1427 | (count == 1) ? "" : "s", this->dir); | |
e881ee23 AS |
1428 | } |
1429 | } | |
1430 | else | |
1431 | { | |
1432 | e = this->db->query(this->db, | |
b8db66de AS |
1433 | "SELECT h.id, h.hash, f.id, f.name, d.id, d.path, p.id, p.name " |
1434 | "FROM file_hashes AS h " | |
1435 | "JOIN files AS f ON h.file = f.id " | |
1436 | "JOIN directories AS d ON f.dir = d.id " | |
60da0153 AS |
1437 | "JOIN versions AS v ON h.version = v.id " |
1438 | "JOIN products AS p on v.product = p.id " | |
b8db66de AS |
1439 | "WHERE h.algo = ? " |
1440 | "ORDER BY d.path, f.name, p.name, h.hash", | |
60da0153 | 1441 | DB_INT, this->algo, DB_INT, DB_TEXT, DB_INT, DB_TEXT, |
b8db66de | 1442 | DB_INT, DB_TEXT, DB_INT, DB_TEXT); |
e881ee23 AS |
1443 | if (e) |
1444 | { | |
b8db66de AS |
1445 | while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir, &pid, |
1446 | &product)) | |
e881ee23 | 1447 | { |
b8db66de | 1448 | if (did != did_old) |
e881ee23 | 1449 | { |
60da0153 | 1450 | printf("%6d: %s\n", did, dir); |
b8db66de AS |
1451 | did_old = did; |
1452 | } | |
1453 | if (fid != fid_old) | |
1454 | { | |
60da0153 | 1455 | printf("%6d: %s\n", fid, file); |
e881ee23 | 1456 | fid_old = fid; |
b8db66de AS |
1457 | pid_old = 0; |
1458 | } | |
1459 | if (pid != pid_old) | |
1460 | { | |
60da0153 | 1461 | printf("%6d: %s\n", pid, product); |
b8db66de | 1462 | pid_old = pid; |
e881ee23 | 1463 | } |
60da0153 | 1464 | printf("%6d: %s\n", id, hash); |
e881ee23 AS |
1465 | count++; |
1466 | } | |
1467 | e->destroy(e); | |
1468 | ||
358dbe48 AS |
1469 | printf("%d %N value%s found\n", count, pts_meas_algorithm_names, |
1470 | this->algo, (count == 1) ? "" : "s"); | |
e881ee23 AS |
1471 | } |
1472 | } | |
e881ee23 AS |
1473 | } |
1474 | ||
f2a521e7 AS |
1475 | METHOD(attest_db_t, list_measurements, void, |
1476 | private_attest_db_t *this) | |
1477 | { | |
1478 | enumerator_t *e; | |
1479 | chunk_t hash, keyid; | |
1480 | pts_comp_func_name_t *cfn; | |
1481 | char *owner; | |
1482 | int seq_no, pcr, vid, name, qualifier; | |
1483 | int cid, cid_old = 0, kid, kid_old = 0, count = 0; | |
1484 | ||
1485 | if (this->kid && this->cid) | |
1486 | { | |
1487 | e = this->db->query(this->db, | |
1488 | "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner " | |
1489 | "FROM component_hashes AS ch " | |
1490 | "JOIN keys AS k ON k.id = ch.key " | |
1491 | "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? " | |
1492 | "ORDER BY seq_no", | |
e0c66beb | 1493 | DB_INT, this->algo, DB_UINT, this->kid, DB_UINT, this->cid, |
f2a521e7 AS |
1494 | DB_INT, DB_INT, DB_BLOB, DB_TEXT); |
1495 | if (e) | |
1496 | { | |
1497 | while (e->enumerate(e, &seq_no, &pcr, &hash, &owner)) | |
1498 | { | |
1499 | if (this->kid != kid_old) | |
1500 | { | |
0f236aac | 1501 | printf("%4d: %#B '%s'\n", this->kid, &this->key, owner); |
f2a521e7 AS |
1502 | kid_old = this->kid; |
1503 | } | |
e0c66beb | 1504 | printf("%7d %02d %#B\n", seq_no, pcr, &hash); |
f2a521e7 AS |
1505 | count++; |
1506 | } | |
1507 | e->destroy(e); | |
1508 | ||
1509 | printf("%d %N value%s found for component '%s'\n", count, | |
358dbe48 | 1510 | pts_meas_algorithm_names, this->algo, |
f2a521e7 AS |
1511 | (count == 1) ? "" : "s", print_cfn(this->cfn)); |
1512 | } | |
1513 | } | |
1514 | else if (this->cid) | |
1515 | { | |
1516 | e = this->db->query(this->db, | |
1517 | "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner " | |
1518 | "FROM component_hashes AS ch " | |
1519 | "JOIN keys AS k ON k.id = ch.key " | |
1520 | "WHERE ch.algo = ? AND ch.component = ? " | |
1521 | "ORDER BY keyid, seq_no", | |
e0c66beb | 1522 | DB_INT, this->algo, DB_UINT, this->cid, |
f2a521e7 AS |
1523 | DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT); |
1524 | if (e) | |
1525 | { | |
1526 | while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner)) | |
1527 | { | |
1528 | if (kid != kid_old) | |
1529 | { | |
0f236aac | 1530 | printf("%4d: %#B '%s'\n", kid, &keyid, owner); |
f2a521e7 AS |
1531 | kid_old = kid; |
1532 | } | |
e0c66beb | 1533 | printf("%7d %02d %#B\n", seq_no, pcr, &hash); |
f2a521e7 AS |
1534 | count++; |
1535 | } | |
1536 | e->destroy(e); | |
1537 | ||
1538 | printf("%d %N value%s found for component '%s'\n", count, | |
358dbe48 | 1539 | pts_meas_algorithm_names, this->algo, |
f2a521e7 AS |
1540 | (count == 1) ? "" : "s", print_cfn(this->cfn)); |
1541 | } | |
1542 | ||
1543 | } | |
1544 | else if (this->kid) | |
1545 | { | |
1546 | e = this->db->query(this->db, | |
1547 | "SELECT ch.seq_no, ch.pcr, ch.hash, " | |
1548 | "c.id, c.vendor_id, c.name, c.qualifier " | |
1549 | "FROM component_hashes AS ch " | |
1550 | "JOIN components AS c ON c.id = ch.component " | |
1551 | "WHERE ch.algo = ? AND ch.key = ? " | |
1552 | "ORDER BY vendor_id, name, qualifier, seq_no", | |
e0c66beb | 1553 | DB_INT, this->algo, DB_UINT, this->kid, DB_INT, DB_INT, DB_BLOB, |
1b9c613b | 1554 | DB_INT, DB_INT, DB_INT, DB_INT); |
f2a521e7 AS |
1555 | if (e) |
1556 | { | |
1557 | while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name, | |
1558 | &qualifier)) | |
1559 | { | |
1560 | if (cid != cid_old) | |
1561 | { | |
1562 | cfn = pts_comp_func_name_create(vid, name, qualifier); | |
0f236aac | 1563 | printf("%4d: %s\n", cid, print_cfn(cfn)); |
f2a521e7 AS |
1564 | cfn->destroy(cfn); |
1565 | cid_old = cid; | |
1566 | } | |
1567 | printf("%5d %02d %#B\n", seq_no, pcr, &hash); | |
1568 | count++; | |
1569 | } | |
1570 | e->destroy(e); | |
1571 | ||
1572 | printf("%d %N value%s found for key %#B '%s'\n", count, | |
358dbe48 | 1573 | pts_meas_algorithm_names, this->algo, |
f2a521e7 AS |
1574 | (count == 1) ? "" : "s", &this->key, this->owner); |
1575 | } | |
1576 | } | |
1577 | } | |
1578 | ||
b8db66de AS |
1579 | METHOD(attest_db_t, list_sessions, void, |
1580 | private_attest_db_t *this) | |
1581 | { | |
1582 | enumerator_t *e; | |
72631301 AS |
1583 | chunk_t identity; |
1584 | char *product, *device; | |
1585 | int session_id, conn_id, rec, device_len; | |
b8db66de AS |
1586 | time_t created; |
1587 | u_int t; | |
1588 | ||
1589 | e = this->db->query(this->db, | |
29645621 AS |
1590 | "SELECT s.id, s.time, s.connection, s.rec, p.name, d.value, i.value " |
1591 | "FROM sessions AS s " | |
1592 | "LEFT JOIN products AS p ON s.product = p.id " | |
1593 | "LEFT JOIN devices AS d ON s.device = d.id " | |
1594 | "LEFT JOIN identities AS i ON s.identity = i.id " | |
1595 | "ORDER BY s.time DESC", | |
72631301 | 1596 | DB_INT, DB_UINT, DB_INT, DB_INT, DB_TEXT, DB_TEXT, DB_BLOB); |
b8db66de AS |
1597 | if (e) |
1598 | { | |
29645621 AS |
1599 | while (e->enumerate(e, &session_id, &t, &conn_id, &rec, &product, |
1600 | &device, &identity)) | |
b8db66de AS |
1601 | { |
1602 | created = t; | |
1603 | product = product ? product : "-"; | |
72631301 AS |
1604 | device = strlen(device) ? device : "-"; |
1605 | device_len = min(strlen(device), DEVICE_MAX_LEN); | |
b8db66de | 1606 | identity = identity.len ? identity : chunk_from_str("-"); |
97980127 | 1607 | printf("%4d: %T %2d %-20s %.*s%*s%.*s - %N\n", session_id, &created, |
24f59868 | 1608 | this->utc, conn_id, product, device_len, device, |
a00ac1d9 TB |
1609 | DEVICE_MAX_LEN - device_len + 1, " ", (int)identity.len, |
1610 | identity.ptr, TNC_IMV_Action_Recommendation_names, rec); | |
b8db66de AS |
1611 | } |
1612 | e->destroy(e); | |
1613 | } | |
1614 | } | |
1615 | ||
1616 | /** | |
1617 | * Insert a file hash into the database | |
1618 | */ | |
1619 | static bool insert_file_hash(private_attest_db_t *this, | |
1620 | pts_meas_algorithms_t algo, | |
37a73b9c | 1621 | chunk_t measurement, int fid, |
b8db66de | 1622 | int *hashes_added, int *hashes_updated) |
358dbe48 AS |
1623 | { |
1624 | enumerator_t *e; | |
60da0153 AS |
1625 | uint8_t hex_measurement_buf[2*HASH_SIZE_SHA512 + 1]; |
1626 | uint8_t *hex_hash_buf; | |
1627 | chunk_t hex_hash, hex_measurement; | |
358dbe48 | 1628 | char *label; |
37a73b9c | 1629 | bool insert = TRUE, update = FALSE; |
358dbe48 AS |
1630 | |
1631 | label = "could not be created"; | |
1632 | ||
1633 | e = this->db->query(this->db, | |
60da0153 AS |
1634 | "SELECT hash FROM file_hashes " |
1635 | "WHERE algo = ? AND file = ? AND version = ?", | |
1636 | DB_INT, algo, DB_UINT, fid, DB_UINT, this->vid, DB_TEXT); | |
37a73b9c | 1637 | |
358dbe48 AS |
1638 | if (!e) |
1639 | { | |
1640 | printf("file_hashes query failed\n"); | |
1641 | return FALSE; | |
1642 | } | |
60da0153 | 1643 | hex_measurement = chunk_to_hex(measurement, hex_measurement_buf, FALSE); |
37a73b9c | 1644 | |
60da0153 | 1645 | while (e->enumerate(e, &hex_hash_buf)) |
358dbe48 | 1646 | { |
37a73b9c | 1647 | update = TRUE; |
60da0153 | 1648 | hex_hash = chunk_from_str(hex_hash_buf); |
37a73b9c | 1649 | |
60da0153 | 1650 | if (chunk_equals(hex_measurement, hex_hash)) |
f0d4756e AS |
1651 | { |
1652 | label = "exists and equals"; | |
37a73b9c AS |
1653 | insert = FALSE; |
1654 | break; | |
f0d4756e | 1655 | } |
358dbe48 | 1656 | } |
37a73b9c AS |
1657 | e->destroy(e); |
1658 | ||
1659 | if (insert) | |
358dbe48 AS |
1660 | { |
1661 | if (this->db->execute(this->db, NULL, | |
1662 | "INSERT INTO file_hashes " | |
60da0153 AS |
1663 | "(file, version, algo, hash) " |
1664 | "VALUES (?, ?, ?, ?)", | |
1665 | DB_UINT, fid, DB_UINT, this->vid, | |
1666 | DB_INT, algo, DB_TEXT, hex_measurement) != 1) | |
37a73b9c AS |
1667 | { |
1668 | printf("file_hash insertion failed\n"); | |
1669 | return FALSE; | |
1670 | } | |
1671 | if (update) | |
1672 | { | |
1673 | label = "updated"; | |
1674 | (*hashes_updated)++; | |
1675 | } | |
1676 | else | |
358dbe48 AS |
1677 | { |
1678 | label = "created"; | |
1679 | (*hashes_added)++; | |
1680 | } | |
1681 | } | |
37a73b9c | 1682 | printf(" %#B - %s\n", &measurement, label); |
358dbe48 AS |
1683 | return TRUE; |
1684 | } | |
1685 | ||
60da0153 AS |
1686 | /** |
1687 | * Add a package version | |
1688 | */ | |
1689 | static bool add_version(private_attest_db_t *this) | |
1690 | { | |
1691 | int vid, security_old, security, blacklist_old, blacklist; | |
1692 | time_t t = time(NULL); | |
1693 | enumerator_t *e; | |
1694 | bool success; | |
1695 | ||
1696 | security = this->package_state == OS_PACKAGE_STATE_SECURITY; | |
1697 | blacklist = this->package_state == OS_PACKAGE_STATE_BLACKLIST; | |
1698 | ||
1699 | e = this->db->query(this->db, | |
1700 | "SELECT id, security, blacklist FROM versions " | |
1701 | "WHERE package = ? AND product = ? AND release = ?", | |
1702 | DB_UINT, this->gid, DB_UINT, this->pid, DB_TEXT, this->version, | |
1703 | DB_INT, DB_INT, DB_INT, DB_INT); | |
1704 | if (e) | |
1705 | { | |
1706 | if (e->enumerate(e, &vid, &security_old, &blacklist_old)) | |
1707 | { | |
1708 | this->vid = vid; | |
1709 | } | |
1710 | e->destroy(e); | |
1711 | } | |
1712 | if (this->vid) | |
1713 | { | |
1714 | if (security != security_old || blacklist != blacklist_old) | |
1715 | { | |
1716 | /* update security and/or blacklist flag */ | |
1717 | success = this->db->execute(this->db, NULL, "UPDATE versions " | |
1718 | "SET security = ?, blacklist = ?, time = ? WHERE id = ?", | |
1719 | DB_INT, security, DB_INT, blacklist, DB_INT, t, | |
1720 | DB_INT, this->vid) == 1; | |
1721 | ||
1722 | printf("'%s' package %s (%s)%N %s updated in database\n", | |
1723 | this->product, this->package, this->version, | |
1724 | os_package_state_names, this->package_state, | |
1725 | success ? "" : "could not be "); | |
1726 | } | |
1727 | else | |
1728 | { | |
1729 | success = TRUE; | |
1730 | ||
1731 | printf("'%s' package %s (%s)%N exists in database\n", | |
1732 | this->product, this->package, this->version, | |
1733 | os_package_state_names, this->package_state); | |
1734 | } | |
1735 | return success; | |
1736 | } | |
1737 | ||
1738 | /* create a new version */ | |
1739 | success = this->db->execute(this->db, NULL, | |
1740 | "INSERT INTO versions " | |
1741 | "(package, product, release, security, blacklist, time) " | |
1742 | "VALUES (?, ?, ?, ?, ?, ?)", | |
1743 | DB_UINT, this->gid, DB_INT, this->pid, DB_TEXT, | |
1744 | this->version, DB_INT, security, DB_INT, blacklist, | |
1745 | DB_INT, t) == 1; | |
1746 | ||
1747 | printf("'%s' package %s (%s)%N %sinserted into database\n", | |
1748 | this->product, this->package, this->version, | |
1749 | os_package_state_names, this->package_state, | |
1750 | success ? "" : "could not be "); | |
1751 | ||
1752 | return success; | |
1753 | } | |
1754 | ||
b8db66de AS |
1755 | /** |
1756 | * Add hash measurement for a single file or all files in a directory | |
1757 | */ | |
1758 | static bool add_hash(private_attest_db_t *this) | |
f4159ff8 | 1759 | { |
0731d41c MW |
1760 | char *pathname, *filename, *label; |
1761 | const char *sep; | |
b8db66de | 1762 | pts_file_meas_t *measurements; |
37a73b9c | 1763 | chunk_t measurement; |
b8db66de | 1764 | hasher_t *hasher = NULL; |
b8db66de | 1765 | int fid, files_added = 0, hashes_added = 0, hashes_updated = 0; |
b8db66de AS |
1766 | enumerator_t *enumerator, *e; |
1767 | ||
37a73b9c | 1768 | if (!this->meas_dir) |
b8db66de | 1769 | { |
37a73b9c | 1770 | this->meas_dir = strdup(this->dir); |
b8db66de | 1771 | } |
0731d41c | 1772 | sep = get_separator(this->meas_dir); |
358dbe48 | 1773 | |
b8db66de AS |
1774 | if (this->fid) |
1775 | { | |
1776 | /* build pathname from directory path and relative filename */ | |
37a73b9c | 1777 | if (asprintf(&pathname, "%s%s%s", this->meas_dir, sep, this->file) == -1) |
0f236aac AS |
1778 | { |
1779 | return FALSE; | |
1780 | } | |
b8db66de AS |
1781 | measurements = pts_file_meas_create_from_path(0, pathname, FALSE, |
1782 | TRUE, this->algo); | |
1783 | free(pathname); | |
1784 | } | |
1785 | else | |
1786 | { | |
37a73b9c | 1787 | measurements = pts_file_meas_create_from_path(0, this->meas_dir, TRUE, |
b8db66de AS |
1788 | TRUE, this->algo); |
1789 | } | |
1790 | if (!measurements) | |
1791 | { | |
1792 | printf("file measurement failed\n"); | |
1793 | DESTROY_IF(hasher); | |
1794 | return FALSE; | |
1795 | } | |
1796 | ||
1797 | enumerator = measurements->create_enumerator(measurements); | |
1798 | while (enumerator->enumerate(enumerator, &filename, &measurement)) | |
1799 | { | |
1800 | if (this->fid) | |
0f236aac | 1801 | { |
b8db66de AS |
1802 | /* a single file already exists */ |
1803 | filename = this->file; | |
1804 | fid = this->fid; | |
1805 | label = "exists"; | |
0f236aac | 1806 | } |
b8db66de | 1807 | else |
0f236aac AS |
1808 | { |
1809 | /* retrieve or create filename */ | |
1810 | label = "could not be created"; | |
1811 | ||
1812 | e = this->db->query(this->db, | |
b8db66de AS |
1813 | "SELECT id FROM files WHERE name = ? AND dir = ?", |
1814 | DB_TEXT, filename, DB_INT, this->did, DB_INT); | |
0f236aac AS |
1815 | if (!e) |
1816 | { | |
1817 | printf("files query failed\n"); | |
1818 | break; | |
1819 | } | |
1820 | if (e->enumerate(e, &fid)) | |
1821 | { | |
1822 | label = "exists"; | |
1823 | } | |
1824 | else | |
1825 | { | |
1826 | if (this->db->execute(this->db, &fid, | |
b8db66de AS |
1827 | "INSERT INTO files (name, dir) VALUES (?, ?)", |
1828 | DB_TEXT, filename, DB_INT, this->did) == 1) | |
0f236aac AS |
1829 | { |
1830 | label = "created"; | |
1831 | files_added++; | |
1832 | } | |
1833 | } | |
1834 | e->destroy(e); | |
b8db66de AS |
1835 | } |
1836 | printf("%4d: %s - %s\n", fid, filename, label); | |
0f236aac | 1837 | |
b8db66de | 1838 | /* compute file measurement hash */ |
37a73b9c | 1839 | if (!insert_file_hash(this, this->algo, measurement, fid, |
b8db66de AS |
1840 | &hashes_added, &hashes_updated)) |
1841 | { | |
1842 | break; | |
1843 | } | |
b8db66de AS |
1844 | } |
1845 | enumerator->destroy(enumerator); | |
1846 | ||
37a73b9c AS |
1847 | printf("%d measurements, added %d new files, %d file hashes, " |
1848 | "updated %d file hashes\n", | |
1849 | measurements->get_file_count(measurements), | |
1850 | files_added, hashes_added, hashes_updated); | |
b8db66de AS |
1851 | measurements->destroy(measurements); |
1852 | ||
1853 | return TRUE; | |
1854 | } | |
1855 | ||
1856 | METHOD(attest_db_t, add, bool, | |
1857 | private_attest_db_t *this) | |
1858 | { | |
60da0153 AS |
1859 | /* insert package version */ |
1860 | if (this->version_set && this->gid && this->pid) | |
1861 | { | |
1862 | if (!add_version(this)) | |
1863 | { | |
1864 | return FALSE; | |
1865 | } | |
1866 | } | |
b8db66de | 1867 | |
b8db66de AS |
1868 | /* add directory or file hash measurement for a given product */ |
1869 | if (this->did && this->pid) | |
1870 | { | |
1871 | return add_hash(this); | |
0f236aac | 1872 | } |
1bb6a086 | 1873 | |
60da0153 | 1874 | return FALSE; |
f4159ff8 AS |
1875 | } |
1876 | ||
1877 | METHOD(attest_db_t, delete, bool, | |
1878 | private_attest_db_t *this) | |
1879 | { | |
2b28a131 | 1880 | bool success; |
1f179c63 AS |
1881 | int id, count = 0; |
1882 | char *name; | |
1883 | enumerator_t *e; | |
2b28a131 | 1884 | |
838f683c AS |
1885 | /* delete a file measurement hash for a given product */ |
1886 | if (this->algo && this->pid && this->fid) | |
1887 | { | |
1888 | success = this->db->execute(this->db, NULL, | |
60da0153 AS |
1889 | "DELETE FROM file_hashes AS h " |
1890 | "JOIN versions AS v ON h.version = v.id " | |
1891 | "WHERE h.algo = ? AND v.product = ? AND h.file = ?", | |
838f683c | 1892 | DB_UINT, this->algo, DB_UINT, this->pid, |
b8db66de | 1893 | DB_UINT, this->fid) > 0; |
838f683c | 1894 | |
0731d41c MW |
1895 | printf("%4d: %s%s%s\n", this->fid, this->dir, get_separator(this->dir), |
1896 | this->file); | |
838f683c AS |
1897 | printf("%N value for product '%s' %sdeleted from database\n", |
1898 | pts_meas_algorithm_names, this->algo, this->product, | |
1899 | success ? "" : "could not be "); | |
1900 | ||
1901 | return success; | |
1902 | } | |
1903 | ||
fa1baac3 | 1904 | /* delete product/file entries */ |
2b28a131 AS |
1905 | if (this->pid && (this->fid || this->did)) |
1906 | { | |
fa1baac3 AS |
1907 | success = this->db->execute(this->db, NULL, |
1908 | "DELETE FROM product_file " | |
1909 | "WHERE product = ? AND file = ?", | |
1910 | DB_UINT, this->pid, | |
1911 | DB_UINT, this->fid ? this->fid : this->did) > 0; | |
1912 | ||
1913 | printf("product/file pair (%d/%d) %sdeleted from database\n", | |
1914 | this->pid, this->fid ? this->fid : this->did, | |
1915 | success ? "" : "could not be "); | |
1916 | ||
1917 | return success; | |
2b28a131 AS |
1918 | } |
1919 | ||
f2a521e7 | 1920 | if (this->cid) |
2b28a131 AS |
1921 | { |
1922 | success = this->db->execute(this->db, NULL, | |
f2a521e7 AS |
1923 | "DELETE FROM components WHERE id = ?", |
1924 | DB_UINT, this->cid) > 0; | |
2b28a131 | 1925 | |
f2a521e7 AS |
1926 | printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn), |
1927 | success ? "" : "could not be "); | |
1928 | return success; | |
1929 | } | |
1930 | ||
1f179c63 | 1931 | if (this->fid) |
f2a521e7 AS |
1932 | { |
1933 | success = this->db->execute(this->db, NULL, | |
1f179c63 AS |
1934 | "DELETE FROM files WHERE id = ?", |
1935 | DB_UINT, this->fid) > 0; | |
f2a521e7 | 1936 | |
1f179c63 | 1937 | printf("file '%s%s%s' %sdeleted from database\n", this->dir, |
0731d41c | 1938 | get_separator(this->dir), this->file, |
2b28a131 AS |
1939 | success ? "" : "could not be "); |
1940 | return success; | |
1941 | } | |
1942 | ||
1f179c63 | 1943 | if (this->did) |
2b28a131 | 1944 | { |
1f179c63 AS |
1945 | e = this->db->query(this->db, |
1946 | "SELECT id, name FROM files WHERE dir = ? ORDER BY name", | |
1947 | DB_INT, this->did, DB_INT, DB_TEXT); | |
1948 | if (e) | |
1949 | { | |
1950 | while (e->enumerate(e, &id, &name)) | |
1951 | { | |
1952 | printf("%4d: %s\n", id, name); | |
1953 | count++; | |
1954 | } | |
1955 | e->destroy(e); | |
2b28a131 | 1956 | |
1f179c63 AS |
1957 | if (count) |
1958 | { | |
1959 | printf("%d dependent file%s found, " | |
1960 | "directory '%s' could not deleted\n", | |
1961 | count, (count == 1) ? "" : "s", this->dir); | |
1962 | return FALSE; | |
1963 | } | |
1964 | } | |
1965 | success = this->db->execute(this->db, NULL, | |
1966 | "DELETE FROM directories WHERE id = ?", | |
1967 | DB_UINT, this->did) > 0; | |
1968 | printf("directory '%s' %sdeleted from database\n", this->dir, | |
2b28a131 AS |
1969 | success ? "" : "could not be "); |
1970 | return success; | |
1971 | } | |
1972 | ||
f2a521e7 | 1973 | if (this->kid) |
2b28a131 AS |
1974 | { |
1975 | success = this->db->execute(this->db, NULL, | |
f2a521e7 AS |
1976 | "DELETE FROM keys WHERE id = ?", |
1977 | DB_UINT, this->kid) > 0; | |
2b28a131 | 1978 | |
f2a521e7 | 1979 | printf("key %#B %sdeleted from database\n", &this->key, |
2b28a131 AS |
1980 | success ? "" : "could not be "); |
1981 | return success; | |
1982 | } | |
f2a521e7 | 1983 | if (this->pid) |
d37abe0f AS |
1984 | { |
1985 | success = this->db->execute(this->db, NULL, | |
f2a521e7 AS |
1986 | "DELETE FROM products WHERE id = ?", |
1987 | DB_UINT, this->pid) > 0; | |
d37abe0f | 1988 | |
f2a521e7 | 1989 | printf("product '%s' %sdeleted from database\n", this->product, |
d37abe0f AS |
1990 | success ? "" : "could not be "); |
1991 | return success; | |
1992 | } | |
1993 | ||
2b28a131 | 1994 | printf("empty delete command\n"); |
f4159ff8 AS |
1995 | return FALSE; |
1996 | } | |
1997 | ||
e881ee23 AS |
1998 | METHOD(attest_db_t, destroy, void, |
1999 | private_attest_db_t *this) | |
2000 | { | |
2001 | DESTROY_IF(this->db); | |
d37abe0f | 2002 | DESTROY_IF(this->cfn); |
1bb6a086 | 2003 | free(this->package); |
e881ee23 | 2004 | free(this->product); |
1bb6a086 | 2005 | free(this->version); |
e881ee23 AS |
2006 | free(this->file); |
2007 | free(this->dir); | |
37a73b9c | 2008 | free(this->meas_dir); |
f2a521e7 AS |
2009 | free(this->owner); |
2010 | free(this->key.ptr); | |
e881ee23 AS |
2011 | free(this); |
2012 | } | |
2013 | ||
2014 | /** | |
2015 | * Described in header. | |
2016 | */ | |
2017 | attest_db_t *attest_db_create(char *uri) | |
2018 | { | |
2019 | private_attest_db_t *this; | |
2020 | ||
2021 | INIT(this, | |
2022 | .public = { | |
d37abe0f AS |
2023 | .set_component = _set_component, |
2024 | .set_cid = _set_cid, | |
f2a521e7 AS |
2025 | .set_directory = _set_directory, |
2026 | .set_did = _set_did, | |
2027 | .set_file = _set_file, | |
2028 | .set_fid = _set_fid, | |
37a73b9c | 2029 | .set_meas_directory = _set_meas_directory, |
f2a521e7 AS |
2030 | .set_key = _set_key, |
2031 | .set_kid = _set_kid, | |
1bb6a086 AS |
2032 | .set_package = _set_package, |
2033 | .set_gid = _set_gid, | |
f2a521e7 AS |
2034 | .set_product = _set_product, |
2035 | .set_pid = _set_pid, | |
1bb6a086 | 2036 | .set_version = _set_version, |
e881ee23 | 2037 | .set_algo = _set_algo, |
0f236aac | 2038 | .set_relative = _set_relative, |
71c7b435 | 2039 | .set_package_state = _set_package_state, |
e0c66beb | 2040 | .set_sequence = _set_sequence, |
f2a521e7 | 2041 | .set_owner = _set_owner, |
81ee269d | 2042 | .set_utc = _set_utc, |
1bb6a086 | 2043 | .list_packages = _list_packages, |
e881ee23 AS |
2044 | .list_products = _list_products, |
2045 | .list_files = _list_files, | |
1f179c63 | 2046 | .list_directories = _list_directories, |
6b55276a | 2047 | .list_components = _list_components, |
ac6dd7d4 | 2048 | .list_devices = _list_devices, |
f2a521e7 | 2049 | .list_keys = _list_keys, |
e881ee23 | 2050 | .list_hashes = _list_hashes, |
f2a521e7 | 2051 | .list_measurements = _list_measurements, |
b8db66de | 2052 | .list_sessions = _list_sessions, |
f4159ff8 AS |
2053 | .add = _add, |
2054 | .delete = _delete, | |
e881ee23 AS |
2055 | .destroy = _destroy, |
2056 | }, | |
e881ee23 AS |
2057 | .db = lib->db->create(lib->db, uri), |
2058 | ); | |
2059 | ||
2060 | if (!this->db) | |
2061 | { | |
2062 | fprintf(stderr, "opening database failed.\n"); | |
2063 | destroy(this); | |
2064 | return NULL; | |
2065 | } | |
2066 | ||
2067 | return &this->public; | |
2068 | } |