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