add directory prefix to file path
[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 * get the directory if there is one from the files tables
149 */
150 static void get_directory(int did, char **directory)
151 {
152 enumerator_t *e;
153 char *dir;
154
155 free(*directory);
156 *directory = strdup("");
157
158 if (did)
159 {
160 e = db->query(db, "SELECT path from files WHERE id = ?",
161 DB_INT, did, DB_TEXT);
162 if (e)
163 {
164 if (e->enumerate(e, &dir))
165 {
166 free(*directory);
167 *directory = strdup(dir);
168 }
169 e->destroy(e);
170 }
171 }
172 }
173
174 /**
175 * ipsec attest --hashes - show all file measurement hashes
176 */
177 static void list_hashes(pts_meas_algorithms_t algo)
178 {
179 enumerator_t *e;
180 chunk_t hash;
181 char *file, *dir, *product;
182 int fid, fid_old = 0, did, did_old = 0, count = 0;
183 bool slash;
184
185 dir = strdup("");
186
187 e = db->query(db,
188 "SELECT f.id, f.path, p.name, fh.hash, fh.directory "
189 "FROM files AS f, products AS p, file_hashes AS fh "
190 "WHERE fh.algo = ? AND f.id = fh.file AND p.id = fh.product "
191 "ORDER BY fh.directory, f.path, p.name",
192 DB_INT, algo, DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT);
193 if (e)
194 {
195 while (e->enumerate(e, &fid, &file, &product, &hash, &did))
196 {
197 if (fid != fid_old || did != did_old)
198 {
199 if (did != did_old)
200 {
201 get_directory(did, &dir);
202 }
203 slash = *file != '/' && dir[max(0, strlen(dir)-1)] != '/';
204 printf("%3d: %s%s%s\n", fid, dir, slash ? "/":"", file);
205 fid_old = fid;
206 did_old = did;
207 }
208 printf(" %#B '%s'\n", &hash, product);
209 count++;
210 }
211 e->destroy(e);
212
213 printf("%d %N value%s found\n", count, hash_algorithm_names,
214 pts_meas_algo_to_hash(algo), (count == 1) ? "" : "s");
215 free(dir);
216 }
217 }
218
219 /**
220 * ipsec attest --hashes - show file measurement hashes for a given product
221 */
222 static void list_hashes_for_product(pts_meas_algorithms_t algo,
223 char *product, int pid)
224 {
225 enumerator_t *e;
226 chunk_t hash;
227 char *file, *dir;
228 int fid, fid_old = 0, did, did_old = 0, count = 0;
229 bool slash;
230
231 dir = strdup("");
232
233 if (pid)
234 {
235 e = db->query(db,
236 "SELECT f.id, f. f.path, fh.hash, fh.directory "
237 "FROM files AS f, file_hashes AS fh "
238 "JOIN products AS p ON p.id = fh.product "
239 "WHERE fh.algo = ? AND p.id = ? AND f.id = fh.file "
240 "ORDER BY fh.directory, f.path",
241 DB_INT, algo, DB_INT, pid, DB_INT, DB_TEXT, DB_BLOB, DB_INT);
242 }
243 else
244 {
245 e = db->query(db,
246 "SELECT f.id, f.path, fh.hash, fh.directory "
247 "FROM files AS f, file_hashes AS fh "
248 "JOIN products AS p ON p.id = fh.product "
249 "WHERE fh.algo = ? AND p.name = ? AND f.id = fh.file "
250 "ORDER BY fh.directory, f.path",
251 DB_INT, algo, DB_TEXT, product, DB_INT, DB_TEXT, DB_BLOB, DB_INT);
252 }
253 if (e)
254 {
255 while (e->enumerate(e, &fid, &file, &hash, &did))
256 {
257 if (fid != fid_old || did != did_old)
258 {
259 if (did != did_old)
260 {
261 get_directory(did, &dir);
262 }
263 slash = *file != '/' && dir[max(0, strlen(dir)-1)] != '/';
264 printf("%3d: %s%s%s\n", fid, dir, slash ? "/":"", file);
265 fid_old = fid;
266 did_old = did;
267 }
268 printf(" %#B\n", &hash);
269 count++;
270 }
271 e->destroy(e);
272
273 printf("%d %N value%s found for product '%s'\n",
274 count, hash_algorithm_names, pts_meas_algo_to_hash(algo),
275 (count == 1) ? "" : "s", product);
276 free(dir);
277 }
278 }
279
280 /**
281 * find file corresponding to primary key fid
282 */
283 static bool fid_to_file(int fid, char **file)
284 {
285 enumerator_t *e;
286 bool found = FALSE;
287 char *f;
288
289 e = db->query(db, "SELECT name FROM products WHERE id = ?",
290 DB_INT, fid, DB_TEXT);
291 if (e)
292 {
293 if (e->enumerate(e, &f))
294 {
295 found = TRUE;
296 *file = strdup(f);
297 }
298 else
299 {
300 printf("no file found with fid %d\n", fid);
301 }
302 e->destroy(e);
303 }
304 return found;
305 }
306
307 /**
308 * find product corresponding to primary key pid
309 */
310 static bool pid_to_product(int pid, char **product)
311 {
312 enumerator_t *e;
313 bool found = FALSE;
314 char *p;
315
316 e = db->query(db, "SELECT name FROM products WHERE id = ?",
317 DB_INT, pid, DB_TEXT);
318 if (e)
319 {
320 if (e->enumerate(e, &p))
321 {
322 found = TRUE;
323 *product = strdup(p);
324 }
325 else
326 {
327 printf("no product found with pid %d\n", pid);
328 }
329 e->destroy(e);
330 }
331 return found;
332 }
333
334 /**
335 * atexit handler to close db on shutdown
336 */
337 static void cleanup(void)
338 {
339 db->destroy(db);
340 }
341
342 static void do_args(int argc, char *argv[])
343 {
344 char *product = NULL, *file = NULL;
345 int fid = 0, pid = 0;
346 pts_meas_algorithms_t algo = PTS_MEAS_ALGO_SHA256;
347
348 enum {
349 OP_UNDEF,
350 OP_USAGE,
351 OP_FILES,
352 OP_PRODUCTS,
353 OP_HASHES,
354 } operation = OP_UNDEF;
355
356 /* reinit getopt state */
357 optind = 0;
358
359 while (TRUE)
360 {
361 int c;
362
363 struct option long_opts[] = {
364 { "help", no_argument, NULL, 'h' },
365 { "files", no_argument, NULL, 'f' },
366 { "products", no_argument, NULL, 'p' },
367 { "hashes", no_argument, NULL, 'H' },
368 { "file", required_argument, NULL, 'F' },
369 { "product", required_argument, NULL, 'P' },
370 { "sha1", no_argument, NULL, '1' },
371 { "sha256", no_argument, NULL, '2' },
372 { "sha384", no_argument, NULL, '3' },
373 { "fid", required_argument, NULL, '4' },
374 { "pid", required_argument, NULL, '5' },
375 { 0,0,0,0 }
376 };
377
378 c = getopt_long(argc, argv, "", long_opts, NULL);
379 switch (c)
380 {
381 case EOF:
382 break;
383 case 'h':
384 operation = OP_USAGE;
385 break;
386 case 'f':
387 operation = OP_FILES;
388 continue;
389 case 'p':
390 operation = OP_PRODUCTS;
391 continue;
392 case 'H':
393 operation = OP_HASHES;
394 continue;
395 case 'F':
396 file = optarg;
397 continue;
398 case 'P':
399 product = optarg;
400 continue;
401 case '1':
402 algo = PTS_MEAS_ALGO_SHA1;
403 continue;
404 case '2':
405 algo = PTS_MEAS_ALGO_SHA256;
406 continue;
407 case '3':
408 algo = PTS_MEAS_ALGO_SHA384;
409 continue;
410 case '4':
411 fid = atoi(optarg);
412 if (!fid_to_file(fid, &file))
413 {
414 exit(EXIT_FAILURE);
415 }
416 continue;
417 case '5':
418 pid = atoi(optarg);
419 if (!pid_to_product(pid, &product))
420 {
421 exit(EXIT_FAILURE);
422 }
423 continue;
424 }
425 break;
426 }
427
428 switch (operation)
429 {
430 case OP_USAGE:
431 usage();
432 break;
433 case OP_PRODUCTS:
434 list_products(file, fid);
435 break;
436 case OP_FILES:
437 list_files(product, pid);
438 break;
439 case OP_HASHES:
440 if ((!product || *product == '\0') && (!file || *file == '\0'))
441 {
442 list_hashes(algo);
443 }
444 else
445 {
446 list_hashes_for_product(algo, product, pid);
447 }
448 break;
449 default:
450 usage();
451 exit(EXIT_FAILURE);
452 }
453
454 if (fid)
455 {
456 free(file);
457 }
458 if (pid)
459 {
460 free(product);
461 }
462
463 }
464
465 int main(int argc, char *argv[])
466 {
467 char *uri;
468
469 atexit(library_deinit);
470
471 /* initialize library */
472 if (!library_init(NULL))
473 {
474 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
475 }
476 if (!lib->plugins->load(lib->plugins, NULL,
477 lib->settings->get_str(lib->settings, "attest.load", "sqlite")))
478 {
479 exit(SS_RC_INITIALIZATION_FAILED);
480 }
481
482 uri = lib->settings->get_str(lib->settings, "attest.database", NULL);
483 if (!uri)
484 {
485 fprintf(stderr, "database URI attest.database not set.\n");
486 exit(SS_RC_INITIALIZATION_FAILED);
487 }
488 db = lib->db->create(lib->db, uri);
489 if (!db)
490 {
491 fprintf(stderr, "opening database failed.\n");
492 exit(SS_RC_INITIALIZATION_FAILED);
493 }
494 atexit(cleanup);
495
496 do_args(argc, argv);
497
498 exit(EXIT_SUCCESS);
499 }
500