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