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