add overall recommendation to session database entry
[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 <tncif_names.h>
23
24 #include "attest_db.h"
25
26 #include "libpts.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 #define IMA_MAX_NAME_LEN 255
31
32 typedef struct private_attest_db_t private_attest_db_t;
33
34 /**
35 * Private data of an attest_db_t object.
36 */
37 struct private_attest_db_t {
38
39 /**
40 * Public members of attest_db_state_t
41 */
42 attest_db_t public;
43
44 /**
45 * Component Functional Name to be queried
46 */
47 pts_comp_func_name_t *cfn;
48
49 /**
50 * Primary key of the Component Functional Name to be queried
51 */
52 int cid;
53
54 /**
55 * TRUE if Component Functional Name has been set
56 */
57 bool comp_set;
58
59 /**
60 * Directory containing the Measurement file to be queried
61 */
62 char *dir;
63
64 /**
65 * Primary key of the directory to be queried
66 */
67 int did;
68
69 /**
70 * Measurement file to be queried
71 */
72 char *file;
73
74 /**
75 * Primary key of measurement file to be queried
76 */
77 int fid;
78
79 /**
80 * AIK to be queried
81 */
82 chunk_t key;
83
84 /**
85 * Primary key of the AIK to be queried
86 */
87 int kid;
88
89 /**
90 * TRUE if AIK has been set
91 */
92 bool key_set;
93
94 /**
95 * Software package to be queried
96 */
97 char *package;
98
99 /**
100 * Primary key of software package to be queried
101 */
102 int gid;
103
104 /**
105 * TRUE if package has been set
106 */
107 bool package_set;
108
109 /**
110 * Software product to be queried
111 */
112 char *product;
113
114 /**
115 * Primary key of software product to be queried
116 */
117 int pid;
118
119 /**
120 * TRUE if product has been set
121 */
122 bool product_set;
123
124 /**
125 * Software package version to be queried
126 */
127 char *version;
128
129 /**
130 * TRUE if version has been set
131 */
132 bool version_set;
133
134 /**
135 * TRUE if relative filenames are to be used
136 */
137 bool relative;
138
139 /**
140 * TRUE if dates are to be displayed in UTC
141 */
142 bool utc;
143
144 /**
145 * Package security state
146 */
147 os_package_state_t security;
148
149 /**
150 * Sequence number for ordering entries
151 */
152 int seq_no;
153
154 /**
155 * File measurement hash algorithm
156 */
157 pts_meas_algorithms_t algo;
158
159 /**
160 * Optional owner (user/host name)
161 */
162 char *owner;
163
164 /**
165 * Attestation database
166 */
167 database_t *db;
168
169 };
170
171 char* print_cfn(pts_comp_func_name_t *cfn)
172 {
173 static char buf[BUF_LEN];
174 char flags[8];
175 int type, vid, name, qualifier, n;
176 enum_name_t *names, *types;
177
178 vid = cfn->get_vendor_id(cfn),
179 name = cfn->get_name(cfn);
180 qualifier = cfn->get_qualifier(cfn);
181 n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier);
182
183 names = pts_components->get_comp_func_names(pts_components, vid);
184 types = pts_components->get_qualifier_type_names(pts_components, vid);
185 type = pts_components->get_qualifier(pts_components, cfn, flags);
186 if (names && types)
187 {
188 n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N",
189 pen_names, vid, names, name, flags, types, type);
190 }
191 return buf;
192 }
193
194 METHOD(attest_db_t, set_component, bool,
195 private_attest_db_t *this, char *comp, bool create)
196 {
197 enumerator_t *e;
198 char *pos1, *pos2;
199 int vid, name, qualifier;
200 pts_comp_func_name_t *cfn;
201
202 if (this->comp_set)
203 {
204 printf("component has already been set\n");
205 return FALSE;
206 }
207
208 /* parse component string */
209 pos1 = strchr(comp, '/');
210 pos2 = strchr(comp, '-');
211 if (!pos1 || !pos2)
212 {
213 printf("component string must have the form \"vendor_id/name-qualifier\"\n");
214 return FALSE;
215 }
216 vid = atoi(comp);
217 name = atoi(pos1 + 1);
218 qualifier = atoi(pos2 + 1);
219 cfn = pts_comp_func_name_create(vid, name, qualifier);
220
221 e = this->db->query(this->db,
222 "SELECT id FROM components "
223 "WHERE vendor_id = ? AND name = ? AND qualifier = ?",
224 DB_UINT, vid, DB_INT, name, DB_INT, qualifier, DB_INT);
225 if (e)
226 {
227 if (e->enumerate(e, &this->cid))
228 {
229 this->comp_set = TRUE;
230 this->cfn = cfn;
231 }
232 e->destroy(e);
233 }
234 if (this->comp_set)
235 {
236 return TRUE;
237 }
238
239 if (!create)
240 {
241 printf("component '%s' not found in database\n", print_cfn(cfn));
242 cfn->destroy(cfn);
243 return FALSE;
244 }
245
246 /* Add a new database entry */
247 this->comp_set = this->db->execute(this->db, &this->cid,
248 "INSERT INTO components (vendor_id, name, qualifier) "
249 "VALUES (?, ?, ?)",
250 DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1;
251
252 printf("component '%s' %sinserted into database\n", print_cfn(cfn),
253 this->comp_set ? "" : "could not be ");
254 if (this->comp_set)
255 {
256 this->cfn = cfn;
257 }
258 else
259 {
260 cfn->destroy(cfn);
261 }
262 return this->comp_set;
263 }
264
265 METHOD(attest_db_t, set_cid, bool,
266 private_attest_db_t *this, int cid)
267 {
268 enumerator_t *e;
269 int vid, name, qualifier;
270
271 if (this->comp_set)
272 {
273 printf("component has already been set\n");
274 return FALSE;
275 }
276 this->cid = cid;
277
278 e = this->db->query(this->db, "SELECT vendor_id, name, qualifier "
279 "FROM components WHERE id = ?",
280 DB_UINT, cid, DB_INT, DB_INT, DB_INT);
281 if (e)
282 {
283 if (e->enumerate(e, &vid, &name, &qualifier))
284 {
285 this->cfn = pts_comp_func_name_create(vid, name, qualifier);
286 this->comp_set = TRUE;
287 }
288 else
289 {
290 printf("no component found with cid %d\n", cid);
291 }
292 e->destroy(e);
293 }
294 return this->comp_set;
295 }
296
297 METHOD(attest_db_t, set_directory, bool,
298 private_attest_db_t *this, char *dir, bool create)
299 {
300 enumerator_t *e;
301 int did;
302 size_t len;
303
304 if (this->did)
305 {
306 printf("directory has already been set\n");
307 return FALSE;
308 }
309
310 /* remove trailing '/' character if not root directory */
311 len = strlen(dir);
312 if (len > 1 && dir[len-1] == '/')
313 {
314 dir[len-1] = '\0';
315 }
316 this->dir = strdup(dir);
317
318 e = this->db->query(this->db,
319 "SELECT id FROM directories WHERE path = ?",
320 DB_TEXT, dir, DB_INT);
321 if (e)
322 {
323 if (e->enumerate(e, &did))
324 {
325 this->did = did;
326 }
327 e->destroy(e);
328 }
329 if (this->did)
330 {
331 return TRUE;
332 }
333
334 if (!create)
335 {
336 printf("directory '%s' not found in database\n", dir);
337 return FALSE;
338 }
339
340 /* Add a new database entry */
341 if (1 == this->db->execute(this->db, &did,
342 "INSERT INTO directories (path) VALUES (?)", DB_TEXT, dir))
343 {
344 this->did = did;
345 }
346 printf("directory '%s' %sinserted into database\n", dir,
347 this->did ? "" : "could not be ");
348
349 return this->did > 0;
350 }
351
352 METHOD(attest_db_t, set_did, bool,
353 private_attest_db_t *this, int did)
354 {
355 enumerator_t *e;
356 char *dir;
357
358 if (this->did)
359 {
360 printf("directory has already been set\n");
361 return FALSE;
362 }
363
364 e = this->db->query(this->db, "SELECT path FROM directories WHERE id = ?",
365 DB_UINT, did, DB_TEXT);
366 if (e)
367 {
368 if (e->enumerate(e, &dir))
369 {
370 this->dir = strdup(dir);
371 this->did = did;
372 }
373 else
374 {
375 printf("no directory found with did %d\n", did);
376 }
377 e->destroy(e);
378 }
379 return this->did > 0;
380 }
381
382 METHOD(attest_db_t, set_file, bool,
383 private_attest_db_t *this, char *file, bool create)
384 {
385 int fid;
386 char *sep;
387 enumerator_t *e;
388
389 if (this->file)
390 {
391 printf("file has already been set\n");
392 return FALSE;
393 }
394 this->file = strdup(file);
395
396 if (!this->did)
397 {
398 return TRUE;
399 }
400 sep = streq(this->dir, "/") ? "" : "/";
401 e = this->db->query(this->db, "SELECT id FROM files "
402 "WHERE dir = ? AND name = ?",
403 DB_INT, this->did, DB_TEXT, file, DB_INT);
404 if (e)
405 {
406 if (e->enumerate(e, &fid))
407 {
408 this->fid = fid;
409 }
410 e->destroy(e);
411 }
412 if (this->fid)
413 {
414 return TRUE;
415 }
416
417 if (!create)
418 {
419 printf("file '%s%s%s' not found in database\n", this->dir, sep, file);
420 return FALSE;
421 }
422
423 /* Add a new database entry */
424 if (1 == this->db->execute(this->db, &fid,
425 "INSERT INTO files (dir, name) VALUES (?, ?)",
426 DB_INT, this->did, DB_TEXT, file))
427 {
428 this->fid = fid;
429 }
430 printf("file '%s%s%s' %sinserted into database\n", this->dir, sep, file,
431 this->fid ? "" : "could not be ");
432
433 return this->fid > 0;
434 }
435
436 METHOD(attest_db_t, set_fid, bool,
437 private_attest_db_t *this, int fid)
438 {
439 enumerator_t *e;
440 int did;
441 char *file;
442
443 if (this->fid)
444 {
445 printf("file has already been set\n");
446 return FALSE;
447 }
448
449 e = this->db->query(this->db, "SELECT dir, name FROM files WHERE id = ?",
450 DB_UINT, fid, DB_INT, DB_TEXT);
451 if (e)
452 {
453 if (e->enumerate(e, &did, &file))
454 {
455 if (did)
456 {
457 set_did(this, did);
458 }
459 this->file = strdup(file);
460 this->fid = fid;
461 }
462 else
463 {
464 printf("no file found with fid %d\n", fid);
465 }
466 e->destroy(e);
467 }
468 return this->fid > 0;
469 }
470
471 METHOD(attest_db_t, set_key, bool,
472 private_attest_db_t *this, chunk_t key, bool create)
473 {
474 enumerator_t *e;
475 char *owner;
476
477 if (this->key_set)
478 {
479 printf("key has already been set\n");
480 return FALSE;
481 }
482 this->key = key;
483
484 e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?",
485 DB_BLOB, this->key, DB_INT, DB_TEXT);
486 if (e)
487 {
488 if (e->enumerate(e, &this->kid, &owner))
489 {
490 free(this->owner);
491 this->owner = strdup(owner);
492 this->key_set = TRUE;
493 }
494 e->destroy(e);
495 }
496 if (this->key_set)
497 {
498 return TRUE;
499 }
500
501 if (!create)
502 {
503 printf("key '%#B' not found in database\n", &this->key);
504 return FALSE;
505 }
506
507 /* Add a new database entry */
508 if (!this->owner)
509 {
510 this->owner = strdup("");
511 }
512 this->key_set = this->db->execute(this->db, &this->kid,
513 "INSERT INTO keys (keyid, owner) VALUES (?, ?)",
514 DB_BLOB, this->key, DB_TEXT, this->owner) == 1;
515
516 printf("key '%#B' %sinserted into database\n", &this->key,
517 this->key_set ? "" : "could not be ");
518
519 return this->key_set;
520
521 };
522
523 METHOD(attest_db_t, set_kid, bool,
524 private_attest_db_t *this, int kid)
525 {
526 enumerator_t *e;
527 chunk_t key;
528 char *owner;
529
530 if (this->key_set)
531 {
532 printf("key has already been set\n");
533 return FALSE;
534 }
535 this->kid = kid;
536
537 e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?",
538 DB_UINT, kid, DB_BLOB, DB_TEXT);
539 if (e)
540 {
541 if (e->enumerate(e, &key, &owner))
542 {
543 this->owner = strdup(owner);
544 this->key = chunk_clone(key);
545 this->key_set = TRUE;
546 }
547 else
548 {
549 printf("no key found with kid %d\n", kid);
550 }
551 e->destroy(e);
552 }
553 return this->key_set;
554
555 };
556
557 METHOD(attest_db_t, set_product, bool,
558 private_attest_db_t *this, char *product, bool create)
559 {
560 enumerator_t *e;
561
562 if (this->product_set)
563 {
564 printf("product has already been set\n");
565 return FALSE;
566 }
567 this->product = strdup(product);
568
569 e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?",
570 DB_TEXT, product, DB_INT);
571 if (e)
572 {
573 if (e->enumerate(e, &this->pid))
574 {
575 this->product_set = TRUE;
576 }
577 e->destroy(e);
578 }
579 if (this->product_set)
580 {
581 return TRUE;
582 }
583
584 if (!create)
585 {
586 printf("product '%s' not found in database\n", product);
587 return FALSE;
588 }
589
590 /* Add a new database entry */
591 this->product_set = this->db->execute(this->db, &this->pid,
592 "INSERT INTO products (name) VALUES (?)",
593 DB_TEXT, product) == 1;
594
595 printf("product '%s' %sinserted into database\n", product,
596 this->product_set ? "" : "could not be ");
597
598 return this->product_set;
599 }
600
601 METHOD(attest_db_t, set_pid, bool,
602 private_attest_db_t *this, int pid)
603 {
604 enumerator_t *e;
605 char *product;
606
607 if (this->product_set)
608 {
609 printf("product has already been set\n");
610 return FALSE;
611 }
612 this->pid = pid;
613
614 e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?",
615 DB_UINT, pid, DB_TEXT);
616 if (e)
617 {
618 if (e->enumerate(e, &product))
619 {
620 this->product = strdup(product);
621 this->product_set = TRUE;
622 }
623 else
624 {
625 printf("no product found with pid %d in database\n", pid);
626 }
627 e->destroy(e);
628 }
629 return this->product_set;
630 }
631
632 METHOD(attest_db_t, set_package, bool,
633 private_attest_db_t *this, char *package, bool create)
634 {
635 enumerator_t *e;
636
637 if (this->package_set)
638 {
639 printf("package has already been set\n");
640 return FALSE;
641 }
642 this->package = strdup(package);
643
644 e = this->db->query(this->db, "SELECT id FROM packages WHERE name = ?",
645 DB_TEXT, package, DB_INT);
646 if (e)
647 {
648 if (e->enumerate(e, &this->gid))
649 {
650 this->package_set = TRUE;
651 }
652 e->destroy(e);
653 }
654 if (this->package_set)
655 {
656 return TRUE;
657 }
658
659 if (!create)
660 {
661 printf("package '%s' not found in database\n", package);
662 return FALSE;
663 }
664
665 /* Add a new database entry */
666 this->package_set = this->db->execute(this->db, &this->gid,
667 "INSERT INTO packages (name) VALUES (?)",
668 DB_TEXT, package) == 1;
669
670 printf("package '%s' %sinserted into database\n", package,
671 this->package_set ? "" : "could not be ");
672
673 return this->package_set;
674 }
675
676 METHOD(attest_db_t, set_gid, bool,
677 private_attest_db_t *this, int gid)
678 {
679 enumerator_t *e;
680 char *package;
681
682 if (this->package_set)
683 {
684 printf("package has already been set\n");
685 return FALSE;
686 }
687 this->gid = gid;
688
689 e = this->db->query(this->db, "SELECT name FROM packages WHERE id = ?",
690 DB_UINT, gid, DB_TEXT);
691 if (e)
692 {
693 if (e->enumerate(e, &package))
694 {
695 this->package = strdup(package);
696 this->package_set = TRUE;
697 }
698 else
699 {
700 printf("no package found with gid %d in database\n", gid);
701 }
702 e->destroy(e);
703 }
704 return this->package_set;
705 }
706
707 METHOD(attest_db_t, set_version, bool,
708 private_attest_db_t *this, char *version)
709 {
710 if (this->version_set)
711 {
712 printf("version has already been set\n");
713 return FALSE;
714 }
715 this->version = strdup(version);
716 this->version_set = TRUE;
717
718 return TRUE;
719 }
720
721
722 METHOD(attest_db_t, set_algo, void,
723 private_attest_db_t *this, pts_meas_algorithms_t algo)
724 {
725 this->algo = algo;
726 }
727
728 METHOD(attest_db_t, set_relative, void,
729 private_attest_db_t *this)
730 {
731 this->relative = TRUE;
732 }
733
734 METHOD(attest_db_t, set_security, void,
735 private_attest_db_t *this, os_package_state_t security)
736 {
737 this->security = security;
738 }
739
740 METHOD(attest_db_t, set_sequence, void,
741 private_attest_db_t *this, int seq_no)
742 {
743 this->seq_no = seq_no;
744 }
745
746 METHOD(attest_db_t, set_owner, void,
747 private_attest_db_t *this, char *owner)
748 {
749 free(this->owner);
750 this->owner = strdup(owner);
751 }
752
753 METHOD(attest_db_t, set_utc, void,
754 private_attest_db_t *this)
755 {
756 this->utc = TRUE;
757 }
758
759 METHOD(attest_db_t, list_components, void,
760 private_attest_db_t *this)
761 {
762 enumerator_t *e;
763 pts_comp_func_name_t *cfn;
764 int seq_no, cid, vid, name, qualifier, count = 0;
765
766 if (this->kid)
767 {
768 e = this->db->query(this->db,
769 "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier "
770 "FROM components AS c "
771 "JOIN key_component AS kc ON c.id = kc.component "
772 "WHERE kc.key = ? ORDER BY kc.seq_no",
773 DB_UINT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT);
774 if (e)
775 {
776 while (e->enumerate(e, &cid, &seq_no, &vid, &name, &qualifier))
777 {
778 cfn = pts_comp_func_name_create(vid, name, qualifier);
779 printf("%4d: #%-2d %s\n", seq_no, cid, print_cfn(cfn));
780 cfn->destroy(cfn);
781 count++;
782 }
783 e->destroy(e);
784 printf("%d component%s found for key %#B\n", count,
785 (count == 1) ? "" : "s", &this->key);
786 }
787 }
788 else
789 {
790 e = this->db->query(this->db,
791 "SELECT id, vendor_id, name, qualifier FROM components "
792 "ORDER BY vendor_id, name, qualifier",
793 DB_INT, DB_INT, DB_INT, DB_INT);
794 if (e)
795 {
796 while (e->enumerate(e, &cid, &vid, &name, &qualifier))
797 {
798 cfn = pts_comp_func_name_create(vid, name, qualifier);
799 printf("%4d: %s\n", cid, print_cfn(cfn));
800 cfn->destroy(cfn);
801 count++;
802 }
803 e->destroy(e);
804 printf("%d component%s found\n", count, (count == 1) ? "" : "s");
805 }
806 }
807 }
808
809 METHOD(attest_db_t, list_devices, void,
810 private_attest_db_t *this)
811 {
812 enumerator_t *e, *e_ar;
813 chunk_t value, ar_id_value = chunk_empty;
814 char *product;
815 time_t timestamp;
816 int id, last_id = 0, ar_id = 0, last_ar_id = 0, device_count = 0;
817 int session_id, rec;
818 u_int32_t ar_id_type;
819 u_int tstamp;
820
821 e = this->db->query(this->db,
822 "SELECT d.id, d.value, s.id, s.time, s.identity, s.rec, p.name "
823 "FROM devices AS d "
824 "JOIN sessions AS s ON d.id = s.device "
825 "JOIN products AS p ON p.id = s.product "
826 "ORDER BY d.value, s.time DESC", DB_INT, DB_BLOB, DB_INT, DB_UINT,
827 DB_INT, DB_INT, DB_TEXT);
828
829 if (e)
830 {
831 while (e->enumerate(e, &id, &value, &session_id, &tstamp, &ar_id, &rec,
832 &product))
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("%4d: %T, %-20s", session_id, &timestamp, this->utc,
842 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\n", TNC_IMV_Action_Recommendation_names, rec);
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, rec;
1523 time_t created;
1524 u_int t;
1525
1526 e = this->db->query(this->db,
1527 "SELECT s.id, s.time, s.connection, s.rec, 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_INT, DB_TEXT, DB_BLOB, DB_BLOB);
1534 if (e)
1535 {
1536 while (e->enumerate(e, &session_id, &t, &conn_id, &rec, &product,
1537 &device, &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\n", session_id, &created,
1545 FALSE, conn_id, product, device.len, device.ptr,
1546 20-device.len, " ", identity.len, identity.ptr,
1547 TNC_IMV_Action_Recommendation_names, rec);
1548 }
1549 e->destroy(e);
1550 }
1551 }
1552
1553 /**
1554 * Insert a file hash into the database
1555 */
1556 static bool insert_file_hash(private_attest_db_t *this,
1557 pts_meas_algorithms_t algo,
1558 chunk_t measurement, int fid, bool ima,
1559 int *hashes_added, int *hashes_updated)
1560 {
1561 enumerator_t *e;
1562 chunk_t hash;
1563 char *label;
1564
1565 label = "could not be created";
1566
1567 e = this->db->query(this->db,
1568 "SELECT hash FROM file_hashes WHERE algo = ? "
1569 "AND file = ? AND product = ? AND device = 0",
1570 DB_INT, algo, DB_UINT, fid, DB_UINT, this->pid, DB_BLOB);
1571 if (!e)
1572 {
1573 printf("file_hashes query failed\n");
1574 return FALSE;
1575 }
1576 if (e->enumerate(e, &hash))
1577 {
1578 if (chunk_equals(measurement, hash))
1579 {
1580 label = "exists and equals";
1581 }
1582 else
1583 {
1584 if (this->db->execute(this->db, NULL,
1585 "UPDATE file_hashes SET hash = ? WHERE algo = ? "
1586 "AND file = ? AND product = ? and device = 0",
1587 DB_BLOB, measurement, DB_INT, algo, DB_UINT, fid,
1588 DB_UINT, this->pid) == 1)
1589 {
1590 label = "updated";
1591 (*hashes_updated)++;
1592 }
1593 }
1594 }
1595 else
1596 {
1597 if (this->db->execute(this->db, NULL,
1598 "INSERT INTO file_hashes "
1599 "(file, product, device, algo, hash) "
1600 "VALUES (?, ?, 0, ?, ?)",
1601 DB_UINT, fid, DB_UINT, this->pid,
1602 DB_INT, algo, DB_BLOB, measurement) == 1)
1603 {
1604 label = "created";
1605 (*hashes_added)++;
1606 }
1607 }
1608 e->destroy(e);
1609
1610 printf(" %#B - %s%s\n", &measurement, ima ? "ima - " : "", label);
1611 return TRUE;
1612 }
1613
1614 /**
1615 * Add hash measurement for a single file or all files in a directory
1616 */
1617 static bool add_hash(private_attest_db_t *this)
1618 {
1619 char *pathname, *filename, *sep, *label, *pos;
1620 char ima_buffer[IMA_MAX_NAME_LEN + 1];
1621 chunk_t measurement, ima_template;
1622 pts_file_meas_t *measurements;
1623 hasher_t *hasher = NULL;
1624 bool ima = FALSE;
1625 int fid, files_added = 0, hashes_added = 0, hashes_updated = 0;
1626 int len, ima_hashes_added = 0, ima_hashes_updated = 0;
1627 enumerator_t *enumerator, *e;
1628
1629 if (this->algo == PTS_MEAS_ALGO_SHA1_IMA)
1630 {
1631 ima = TRUE;
1632 this->algo = PTS_MEAS_ALGO_SHA1;
1633 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1634 if (!hasher)
1635 {
1636 printf("could not create hasher\n");
1637 return FALSE;
1638 }
1639 }
1640 sep = streq(this->dir, "/") ? "" : "/";
1641
1642 if (this->fid)
1643 {
1644 /* build pathname from directory path and relative filename */
1645 if (asprintf(&pathname, "%s%s%s", this->dir, sep, this->file) == -1)
1646 {
1647 return FALSE;
1648 }
1649 measurements = pts_file_meas_create_from_path(0, pathname, FALSE,
1650 TRUE, this->algo);
1651 free(pathname);
1652 }
1653 else
1654 {
1655 measurements = pts_file_meas_create_from_path(0, pathname, TRUE,
1656 TRUE, this->algo);
1657 }
1658 if (!measurements)
1659 {
1660 printf("file measurement failed\n");
1661 DESTROY_IF(hasher);
1662 return FALSE;
1663 }
1664
1665 enumerator = measurements->create_enumerator(measurements);
1666 while (enumerator->enumerate(enumerator, &filename, &measurement))
1667 {
1668 if (this->fid)
1669 {
1670 /* a single file already exists */
1671 filename = this->file;
1672 fid = this->fid;
1673 label = "exists";
1674 }
1675 else
1676 {
1677 /* retrieve or create filename */
1678 label = "could not be created";
1679
1680 e = this->db->query(this->db,
1681 "SELECT id FROM files WHERE name = ? AND dir = ?",
1682 DB_TEXT, filename, DB_INT, this->did, DB_INT);
1683 if (!e)
1684 {
1685 printf("files query failed\n");
1686 break;
1687 }
1688 if (e->enumerate(e, &fid))
1689 {
1690 label = "exists";
1691 }
1692 else
1693 {
1694 if (this->db->execute(this->db, &fid,
1695 "INSERT INTO files (name, dir) VALUES (?, ?)",
1696 DB_TEXT, filename, DB_INT, this->did) == 1)
1697 {
1698 label = "created";
1699 files_added++;
1700 }
1701 }
1702 e->destroy(e);
1703 }
1704 printf("%4d: %s - %s\n", fid, filename, label);
1705
1706 /* compute file measurement hash */
1707 if (!insert_file_hash(this, this->algo, measurement, fid, FALSE,
1708 &hashes_added, &hashes_updated))
1709 {
1710 break;
1711 }
1712 if (!ima)
1713 {
1714 continue;
1715 }
1716
1717 /* compute IMA template hash */
1718 pos = ima_buffer;
1719 len = IMA_MAX_NAME_LEN;
1720 if (!this->relative)
1721 {
1722 strncpy(pos, this->dir, len);
1723 len = max(0, len - strlen(this->dir));
1724 pos = ima_buffer + IMA_MAX_NAME_LEN - len;
1725 strncpy(pos, sep, len);
1726 len = max(0, len - strlen(sep));
1727 pos = ima_buffer + IMA_MAX_NAME_LEN - len;
1728 }
1729 strncpy(pos, filename, len);
1730 ima_buffer[IMA_MAX_NAME_LEN] = '\0';
1731 ima_template = chunk_create(ima_buffer, sizeof(ima_buffer));
1732 if (!hasher->get_hash(hasher, measurement, NULL) ||
1733 !hasher->get_hash(hasher, ima_template, measurement.ptr))
1734 {
1735 printf("could not compute IMA template hash\n");
1736 break;
1737 }
1738 if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA, measurement, fid,
1739 TRUE, &ima_hashes_added, &ima_hashes_updated))
1740 {
1741 break;
1742 }
1743 }
1744 enumerator->destroy(enumerator);
1745
1746 printf("%d measurements, added %d new files, %d file hashes",
1747 measurements->get_file_count(measurements), files_added,
1748 hashes_added);
1749 if (ima)
1750 {
1751 printf(", %d ima hashes", ima_hashes_added);
1752 hasher->destroy(hasher);
1753 }
1754 printf(", updated %d file hashes", hashes_updated);
1755 if (ima)
1756 {
1757 printf(", %d ima hashes", ima_hashes_updated);
1758 }
1759 printf("\n");
1760 measurements->destroy(measurements);
1761
1762 return TRUE;
1763 }
1764
1765 METHOD(attest_db_t, add, bool,
1766 private_attest_db_t *this)
1767 {
1768 bool success = FALSE;
1769
1770 /* add key/component pair */
1771 if (this->kid && this->cid)
1772 {
1773 success = this->db->execute(this->db, NULL,
1774 "INSERT INTO key_component (key, component, seq_no) "
1775 "VALUES (?, ?, ?)",
1776 DB_UINT, this->kid, DB_UINT, this->cid,
1777 DB_UINT, this->seq_no) == 1;
1778
1779 printf("key/component pair (%d/%d) %sinserted into database at "
1780 "position %d\n", this->kid, this->cid,
1781 success ? "" : "could not be ", this->seq_no);
1782
1783 return success;
1784 }
1785
1786 /* add directory or file hash measurement for a given product */
1787 if (this->did && this->pid)
1788 {
1789 return add_hash(this);
1790 }
1791
1792 /* insert package version */
1793 if (this->version_set && this->gid && this->pid)
1794 {
1795 time_t t = time(NULL);
1796
1797 success = this->db->execute(this->db, NULL,
1798 "INSERT INTO versions "
1799 "(package, product, release, security, time) "
1800 "VALUES (?, ?, ?, ?, ?)",
1801 DB_UINT, this->gid, DB_UINT, this->pid, DB_TEXT,
1802 this->version, DB_UINT, this->security, DB_INT, t) == 1;
1803
1804 printf("'%s' package %s (%s)%N %sinserted into database\n",
1805 this->product, this->package, this->version,
1806 os_package_state_names, this->security,
1807 success ? "" : "could not be ");
1808 }
1809 return success;
1810 }
1811
1812 METHOD(attest_db_t, delete, bool,
1813 private_attest_db_t *this)
1814 {
1815 bool success;
1816 int id, count = 0;
1817 char *name;
1818 enumerator_t *e;
1819
1820 /* delete a file measurement hash for a given product */
1821 if (this->algo && this->pid && this->fid)
1822 {
1823 success = this->db->execute(this->db, NULL,
1824 "DELETE FROM file_hashes "
1825 "WHERE algo = ? AND product = ? AND file = ?",
1826 DB_UINT, this->algo, DB_UINT, this->pid,
1827 DB_UINT, this->fid) > 0;
1828
1829 printf("%4d: %s%s%s\n", this->fid, this->dir,
1830 streq(this->dir, "/") ? "" : "/", this->file);
1831 printf("%N value for product '%s' %sdeleted from database\n",
1832 pts_meas_algorithm_names, this->algo, this->product,
1833 success ? "" : "could not be ");
1834
1835 return success;
1836 }
1837
1838 /* delete product/file entries */
1839 if (this->pid && (this->fid || this->did))
1840 {
1841 success = this->db->execute(this->db, NULL,
1842 "DELETE FROM product_file "
1843 "WHERE product = ? AND file = ?",
1844 DB_UINT, this->pid,
1845 DB_UINT, this->fid ? this->fid : this->did) > 0;
1846
1847 printf("product/file pair (%d/%d) %sdeleted from database\n",
1848 this->pid, this->fid ? this->fid : this->did,
1849 success ? "" : "could not be ");
1850
1851 return success;
1852 }
1853
1854 /* delete key/component pair */
1855 if (this->kid && this->cid)
1856 {
1857 success = this->db->execute(this->db, NULL,
1858 "DELETE FROM key_component "
1859 "WHERE key = ? AND component = ?",
1860 DB_UINT, this->kid, DB_UINT, this->cid) > 0;
1861
1862 printf("key/component pair (%d/%d) %sdeleted from database\n",
1863 this->kid, this->cid, success ? "" : "could not be ");
1864 return success;
1865 }
1866
1867 if (this->cid)
1868 {
1869 success = this->db->execute(this->db, NULL,
1870 "DELETE FROM components WHERE id = ?",
1871 DB_UINT, this->cid) > 0;
1872
1873 printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn),
1874 success ? "" : "could not be ");
1875 return success;
1876 }
1877
1878 if (this->fid)
1879 {
1880 success = this->db->execute(this->db, NULL,
1881 "DELETE FROM files WHERE id = ?",
1882 DB_UINT, this->fid) > 0;
1883
1884 printf("file '%s%s%s' %sdeleted from database\n", this->dir,
1885 streq(this->dir, "/") ? "" : "/", this->file,
1886 success ? "" : "could not be ");
1887 return success;
1888 }
1889
1890 if (this->did)
1891 {
1892 e = this->db->query(this->db,
1893 "SELECT id, name FROM files WHERE dir = ? ORDER BY name",
1894 DB_INT, this->did, DB_INT, DB_TEXT);
1895 if (e)
1896 {
1897 while (e->enumerate(e, &id, &name))
1898 {
1899 printf("%4d: %s\n", id, name);
1900 count++;
1901 }
1902 e->destroy(e);
1903
1904 if (count)
1905 {
1906 printf("%d dependent file%s found, "
1907 "directory '%s' could not deleted\n",
1908 count, (count == 1) ? "" : "s", this->dir);
1909 return FALSE;
1910 }
1911 }
1912 success = this->db->execute(this->db, NULL,
1913 "DELETE FROM directories WHERE id = ?",
1914 DB_UINT, this->did) > 0;
1915 printf("directory '%s' %sdeleted from database\n", this->dir,
1916 success ? "" : "could not be ");
1917 return success;
1918 }
1919
1920 if (this->kid)
1921 {
1922 success = this->db->execute(this->db, NULL,
1923 "DELETE FROM keys WHERE id = ?",
1924 DB_UINT, this->kid) > 0;
1925
1926 printf("key %#B %sdeleted from database\n", &this->key,
1927 success ? "" : "could not be ");
1928 return success;
1929 }
1930 if (this->pid)
1931 {
1932 success = this->db->execute(this->db, NULL,
1933 "DELETE FROM products WHERE id = ?",
1934 DB_UINT, this->pid) > 0;
1935
1936 printf("product '%s' %sdeleted from database\n", this->product,
1937 success ? "" : "could not be ");
1938 return success;
1939 }
1940
1941 printf("empty delete command\n");
1942 return FALSE;
1943 }
1944
1945 METHOD(attest_db_t, destroy, void,
1946 private_attest_db_t *this)
1947 {
1948 DESTROY_IF(this->db);
1949 DESTROY_IF(this->cfn);
1950 free(this->package);
1951 free(this->product);
1952 free(this->version);
1953 free(this->file);
1954 free(this->dir);
1955 free(this->owner);
1956 free(this->key.ptr);
1957 free(this);
1958 }
1959
1960 /**
1961 * Described in header.
1962 */
1963 attest_db_t *attest_db_create(char *uri)
1964 {
1965 private_attest_db_t *this;
1966
1967 INIT(this,
1968 .public = {
1969 .set_component = _set_component,
1970 .set_cid = _set_cid,
1971 .set_directory = _set_directory,
1972 .set_did = _set_did,
1973 .set_file = _set_file,
1974 .set_fid = _set_fid,
1975 .set_key = _set_key,
1976 .set_kid = _set_kid,
1977 .set_package = _set_package,
1978 .set_gid = _set_gid,
1979 .set_product = _set_product,
1980 .set_pid = _set_pid,
1981 .set_version = _set_version,
1982 .set_algo = _set_algo,
1983 .set_relative = _set_relative,
1984 .set_security = _set_security,
1985 .set_sequence = _set_sequence,
1986 .set_owner = _set_owner,
1987 .set_utc = _set_utc,
1988 .list_packages = _list_packages,
1989 .list_products = _list_products,
1990 .list_files = _list_files,
1991 .list_directories = _list_directories,
1992 .list_components = _list_components,
1993 .list_devices = _list_devices,
1994 .list_keys = _list_keys,
1995 .list_hashes = _list_hashes,
1996 .list_measurements = _list_measurements,
1997 .list_sessions = _list_sessions,
1998 .add = _add,
1999 .delete = _delete,
2000 .destroy = _destroy,
2001 },
2002 .db = lib->db->create(lib->db, uri),
2003 );
2004
2005 if (!this->db)
2006 {
2007 fprintf(stderr, "opening database failed.\n");
2008 destroy(this);
2009 return NULL;
2010 }
2011
2012 return &this->public;
2013 }