list file measurement hashes
[strongswan.git] / src / libimcv / plugins / imv_attestation / attest.c
1 /*
2 * Copyright (C) 2011 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 #include <getopt.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22
23 #include <debug.h>
24 #include <library.h>
25
26 #include <pts/pts_meas_algo.h>
27
28 #include "attest_usage.h"
29
30 /**
31 * global database handle
32 */
33 database_t *db;
34
35 /**
36 * forward declarations
37 */
38 static void do_args(int argc, char *argv[]);
39
40 /**
41 * ipsec attest --files - show files
42 */
43 static void list_files(char *product, int pid)
44 {
45 enumerator_t *e;
46 char *file;
47 bool select = TRUE;
48 int fid, is_dir, count = 0;
49
50 if (pid)
51 {
52 e = db->query(db,
53 "SELECT f.id, f.type, f.path FROM files AS f "
54 "JOIN product_file AS pf ON f.id = pf.file "
55 "JOIN products AS p ON p.id = pf.product "
56 "WHERE p.id = ? ORDER BY f.path",
57 DB_INT, pid, DB_INT, DB_INT, DB_TEXT);
58 }
59 else if (!product || *product == '\0')
60 {
61 select = FALSE;
62 e = db->query(db,
63 "SELECT id, type, path FROM files "
64 "ORDER BY path",
65 DB_INT, DB_INT, DB_TEXT);
66 }
67 else
68 {
69 e = db->query(db,
70 "SELECT f.id, f.type, f.path FROM files AS f "
71 "JOIN product_file AS pf ON f.id = pf.file "
72 "JOIN products AS p ON p.id = pf.product "
73 "WHERE p.name = ? ORDER BY f.path",
74 DB_TEXT, product, DB_INT, DB_INT, DB_TEXT);
75 }
76 if (e)
77 {
78 while (e->enumerate(e, &fid, &is_dir, &file))
79 {
80 printf("%3d: %s %s\n", fid, is_dir ? "d":" ", file);
81 count++;
82 }
83 e->destroy(e);
84
85 printf("%d file%s found", count, (count == 1) ? "" : "s");
86 if (select)
87 {
88 printf(" for product '%s'", product);
89 }
90 printf("\n");
91 }
92 }
93
94 /**
95 * ipsec attest --products - show products
96 */
97 static void list_products(char *file, int fid)
98 {
99 enumerator_t *e;
100 char *product;
101 bool select = TRUE;
102 int pid, count = 0;
103
104 if (fid)
105 {
106 e = db->query(db,
107 "SELECT p.id, p.name FROM products AS p "
108 "JOIN product_file AS pf ON p.id = pf.product "
109 "JOIN files AS f ON f.id = pf.file "
110 "WHERE f.id = ? ORDER BY p.name",
111 DB_INT, fid, DB_INT, DB_TEXT);
112 }
113 else if (!file || *file == '\0')
114 {
115 select = FALSE;
116 e = db->query(db, "SELECT id, name FROM products "
117 "ORDER BY name",
118 DB_INT, DB_TEXT);
119 }
120 else
121 {
122 e = db->query(db,
123 "SELECT p.id, p.name FROM products AS p "
124 "JOIN product_file AS pf ON p.id = pf.product "
125 "JOIN files AS f ON f.id = pf.file "
126 "WHERE f.path = ? ORDER BY p.name",
127 DB_TEXT, file, DB_INT, DB_TEXT);
128 }
129 if (e)
130 {
131 while (e->enumerate(e, &pid, &product))
132 {
133 printf("%3d: %s\n", pid, product);
134 count++;
135 }
136 e->destroy(e);
137
138 printf("%d product%s found", count, (count == 1) ? "" : "s");
139 if (select)
140 {
141 printf(" for file '%s'", file);
142 }
143 printf("\n");
144 }
145 }
146
147 /**
148 * ipsec attest --hashes - show all file measurement hashes
149 */
150 static void list_hashes(pts_meas_algorithms_t algo)
151 {
152 enumerator_t *e;
153 chunk_t hash;
154 char *file, *product;
155 int fid, fid_old = 0, count = 0;
156
157 e = db->query(db,
158 "SELECT f.id, f.path, p.name, fh.hash "
159 "FROM files AS f, products AS p, file_hashes AS fh "
160 "WHERE fh.algo = ? AND f.id = fh.file AND p.id = fh.product "
161 "ORDER BY f.path",
162 DB_INT, algo, DB_INT, DB_TEXT, DB_TEXT, DB_BLOB);
163 if (e)
164 {
165 while (e->enumerate(e, &fid, &file, &product, &hash))
166 {
167 if (fid != fid_old)
168 {
169 printf("%3d: %s\n", fid, file);
170 fid_old = fid;
171 }
172 printf(" %#B '%s'\n", &hash, product);
173 count++;
174 }
175 e->destroy(e);
176
177 printf("%d %N value%s found\n", count, hash_algorithm_names,
178 pts_meas_algo_to_hash(algo), (count == 1) ? "" : "s");
179 }
180 }
181
182 /**
183 * ipsec attest --hashes - show file measurement hashes for a given product
184 */
185 static void list_hashes_for_product(pts_meas_algorithms_t algo,
186 char *product, int pid)
187 {
188 enumerator_t *e;
189 chunk_t hash;
190 char *file;
191 int fid, fid_old = 0, count = 0;
192
193 if (pid)
194 {
195 e = db->query(db,
196 "SELECT f.id, f.path, fh.hash "
197 "FROM files AS f, file_hashes AS fh "
198 "JOIN products AS p ON p.id = fh.product "
199 "WHERE fh.algo = ? AND p.id = ? AND f.id = fh.file "
200 "ORDER BY f.path",
201 DB_INT, algo, DB_INT, pid, DB_INT, DB_TEXT, DB_BLOB);
202 }
203 else
204 {
205 e = db->query(db,
206 "SELECT f.id, f.path, fh.hash "
207 "FROM files AS f, file_hashes AS fh "
208 "JOIN products AS p ON p.id = fh.product "
209 "WHERE fh.algo = ? AND p.name = ? AND f.id = fh.file "
210 "ORDER BY f.path",
211 DB_INT, algo, DB_TEXT, product, DB_INT, DB_TEXT, DB_BLOB);
212 }
213 if (e)
214 {
215 while (e->enumerate(e, &fid, &file, &hash))
216 {
217 if (fid != fid_old)
218 {
219 printf("%3d: %s\n", fid, file);
220 fid_old = fid;
221 }
222 printf(" %#B\n", &hash);
223 count++;
224 }
225 e->destroy(e);
226
227 printf("%d %N value%s found for product '%s'\n",
228 count, hash_algorithm_names, pts_meas_algo_to_hash(algo),
229 (count == 1) ? "" : "s", product);
230 }
231 }
232
233 /**
234 * find file corresponding to primary key fid
235 */
236 static bool fid_to_file(int fid, char **file)
237 {
238 enumerator_t *e;
239 bool found = FALSE;
240 char *f;
241
242 e = db->query(db, "SELECT name FROM products WHERE id = ?",
243 DB_INT, fid, DB_TEXT);
244 if (e)
245 {
246 if (e->enumerate(e, &f))
247 {
248 found = TRUE;
249 *file = strdup(f);
250 }
251 else
252 {
253 printf("no file found with fid %d\n", fid);
254 }
255 e->destroy(e);
256 }
257 return found;
258 }
259
260 /**
261 * find product corresponding to primary key pid
262 */
263 static bool pid_to_product(int pid, char **product)
264 {
265 enumerator_t *e;
266 bool found = FALSE;
267 char *p;
268
269 e = db->query(db, "SELECT name FROM products WHERE id = ?",
270 DB_INT, pid, DB_TEXT);
271 if (e)
272 {
273 if (e->enumerate(e, &p))
274 {
275 found = TRUE;
276 *product = strdup(p);
277 }
278 else
279 {
280 printf("no product found with pid %d\n", pid);
281 }
282 e->destroy(e);
283 }
284 return found;
285 }
286
287 /**
288 * atexit handler to close db on shutdown
289 */
290 static void cleanup(void)
291 {
292 db->destroy(db);
293 }
294
295 static void do_args(int argc, char *argv[])
296 {
297 char *product = NULL, *file = NULL;
298 int fid = 0, pid = 0;
299 pts_meas_algorithms_t algo = PTS_MEAS_ALGO_SHA256;
300
301 enum {
302 OP_UNDEF,
303 OP_USAGE,
304 OP_FILES,
305 OP_PRODUCTS,
306 OP_HASHES,
307 } operation = OP_UNDEF;
308
309 /* reinit getopt state */
310 optind = 0;
311
312 while (TRUE)
313 {
314 int c;
315
316 struct option long_opts[] = {
317 { "help", no_argument, NULL, 'h' },
318 { "files", no_argument, NULL, 'f' },
319 { "products", no_argument, NULL, 'p' },
320 { "hashes", no_argument, NULL, 'H' },
321 { "file", required_argument, NULL, 'F' },
322 { "product", required_argument, NULL, 'P' },
323 { "sha1", no_argument, NULL, '1' },
324 { "sha256", no_argument, NULL, '2' },
325 { "sha384", no_argument, NULL, '3' },
326 { "fid", required_argument, NULL, '4' },
327 { "pid", required_argument, NULL, '5' },
328 { 0,0,0,0 }
329 };
330
331 c = getopt_long(argc, argv, "", long_opts, NULL);
332 switch (c)
333 {
334 case EOF:
335 break;
336 case 'h':
337 operation = OP_USAGE;
338 break;
339 case 'f':
340 operation = OP_FILES;
341 continue;
342 case 'p':
343 operation = OP_PRODUCTS;
344 continue;
345 case 'H':
346 operation = OP_HASHES;
347 continue;
348 case 'F':
349 file = optarg;
350 continue;
351 case 'P':
352 product = optarg;
353 continue;
354 case '1':
355 algo = PTS_MEAS_ALGO_SHA1;
356 continue;
357 case '2':
358 algo = PTS_MEAS_ALGO_SHA256;
359 continue;
360 case '3':
361 algo = PTS_MEAS_ALGO_SHA384;
362 continue;
363 case '4':
364 fid = atoi(optarg);
365 if (!fid_to_file(fid, &file))
366 {
367 exit(EXIT_FAILURE);
368 }
369 continue;
370 case '5':
371 pid = atoi(optarg);
372 if (!pid_to_product(pid, &product))
373 {
374 exit(EXIT_FAILURE);
375 }
376 continue;
377 }
378 break;
379 }
380
381 switch (operation)
382 {
383 case OP_USAGE:
384 usage();
385 break;
386 case OP_PRODUCTS:
387 list_products(file, fid);
388 break;
389 case OP_FILES:
390 list_files(product, pid);
391 break;
392 case OP_HASHES:
393 if ((!product || *product == '\0') && (!file || *file == '\0'))
394 {
395 list_hashes(algo);
396 }
397 else
398 {
399 list_hashes_for_product(algo, product, pid);
400 }
401 break;
402 default:
403 usage();
404 exit(EXIT_FAILURE);
405 }
406
407 if (fid)
408 {
409 free(file);
410 }
411 if (pid)
412 {
413 free(product);
414 }
415
416 }
417
418 int main(int argc, char *argv[])
419 {
420 char *uri;
421
422 atexit(library_deinit);
423
424 /* initialize library */
425 if (!library_init(NULL))
426 {
427 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
428 }
429 if (!lib->plugins->load(lib->plugins, NULL,
430 lib->settings->get_str(lib->settings, "attest.load", "sqlite")))
431 {
432 exit(SS_RC_INITIALIZATION_FAILED);
433 }
434
435 uri = lib->settings->get_str(lib->settings, "attest.database", NULL);
436 if (!uri)
437 {
438 fprintf(stderr, "database URI attest.database not set.\n");
439 exit(SS_RC_INITIALIZATION_FAILED);
440 }
441 db = lib->db->create(lib->db, uri);
442 if (!db)
443 {
444 fprintf(stderr, "opening database failed.\n");
445 exit(SS_RC_INITIALIZATION_FAILED);
446 }
447 atexit(cleanup);
448
449 do_args(argc, argv);
450
451 exit(EXIT_SUCCESS);
452 }
453