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