pts_file_meas.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. * Copyright (C) 2011 Sansar Choinyambuu
  3. * Copyright (C) 2014 Andreas Steffen
  4. * HSR Hochschule fuer Technik Rapperswil
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. */
  16. #include "pts_file_meas.h"
  17. #include <collections/linked_list.h>
  18. #include <utils/debug.h>
  19. #include <sys/stat.h>
  20. #include <libgen.h>
  21. #include <errno.h>
  22. typedef struct private_pts_file_meas_t private_pts_file_meas_t;
  23. /**
  24. * Private data of a pts_file_meas_t object.
  25. *
  26. */
  27. struct private_pts_file_meas_t {
  28. /**
  29. * Public pts_file_meas_t interface.
  30. */
  31. pts_file_meas_t public;
  32. /**
  33. * ID of PTS File Measurement Request
  34. */
  35. uint16_t request_id;
  36. /**
  37. * List of File Measurements
  38. */
  39. linked_list_t *list;
  40. };
  41. typedef struct entry_t entry_t;
  42. /**
  43. * PTS File Measurement entry
  44. */
  45. struct entry_t {
  46. char *filename;
  47. chunk_t measurement;
  48. };
  49. /**
  50. * Free an entry_t object
  51. */
  52. static void free_entry(entry_t *entry)
  53. {
  54. if (entry)
  55. {
  56. free(entry->filename);
  57. free(entry->measurement.ptr);
  58. free(entry);
  59. }
  60. }
  61. METHOD(pts_file_meas_t, get_request_id, uint16_t,
  62. private_pts_file_meas_t *this)
  63. {
  64. return this->request_id;
  65. }
  66. METHOD(pts_file_meas_t, get_file_count, int,
  67. private_pts_file_meas_t *this)
  68. {
  69. return this->list->get_count(this->list);
  70. }
  71. METHOD(pts_file_meas_t, add, void,
  72. private_pts_file_meas_t *this, char *filename, chunk_t measurement)
  73. {
  74. entry_t *entry;
  75. entry = malloc_thing(entry_t);
  76. entry->filename = strdup(filename);
  77. entry->measurement = chunk_clone(measurement);
  78. this->list->insert_last(this->list, entry);
  79. }
  80. CALLBACK(entry_filter, bool,
  81. void *null, enumerator_t *orig, va_list args)
  82. {
  83. entry_t *entry;
  84. chunk_t *measurement;
  85. char **filename;
  86. VA_ARGS_VGET(args, filename, measurement);
  87. if (orig->enumerate(orig, &entry))
  88. {
  89. *filename = entry->filename;
  90. *measurement = entry->measurement;
  91. return TRUE;
  92. }
  93. return FALSE;
  94. }
  95. METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
  96. private_pts_file_meas_t *this)
  97. {
  98. return enumerator_create_filter(this->list->create_enumerator(this->list),
  99. entry_filter, NULL, NULL);
  100. }
  101. METHOD(pts_file_meas_t, check, bool,
  102. private_pts_file_meas_t *this, pts_database_t *pts_db, int pid,
  103. pts_meas_algorithms_t algo)
  104. {
  105. enumerator_t *enumerator, *e;
  106. entry_t *entry;
  107. chunk_t hash;
  108. int count_ok = 0, count_not_found = 0, count_differ = 0;
  109. status_t status;
  110. enumerator = this->list->create_enumerator(this->list);
  111. while (enumerator->enumerate(enumerator, &entry))
  112. {
  113. status = NOT_FOUND;
  114. e = pts_db->create_file_meas_enumerator(pts_db, pid, algo,
  115. entry->filename);
  116. if (e)
  117. {
  118. while (e->enumerate(e, &hash))
  119. {
  120. if (chunk_equals(entry->measurement, hash))
  121. {
  122. status = SUCCESS;
  123. break;
  124. }
  125. else
  126. {
  127. status = VERIFY_ERROR;
  128. }
  129. }
  130. e->destroy(e);
  131. }
  132. else
  133. {
  134. status = FAILED;
  135. }
  136. switch (status)
  137. {
  138. case SUCCESS:
  139. DBG3(DBG_PTS, " %#B for '%s' is ok", &entry->measurement,
  140. entry->filename);
  141. count_ok++;
  142. break;
  143. case NOT_FOUND:
  144. DBG2(DBG_PTS, " %#B for '%s' not found", &entry->measurement,
  145. entry->filename);
  146. count_not_found++;
  147. break;
  148. case VERIFY_ERROR:
  149. DBG1(DBG_PTS, " %#B for '%s' differs", &entry->measurement,
  150. entry->filename);
  151. count_differ++;
  152. break;
  153. case FAILED:
  154. default:
  155. DBG1(DBG_PTS, " %#B for '%s' failed", &entry->measurement,
  156. entry->filename);
  157. }
  158. }
  159. enumerator->destroy(enumerator);
  160. DBG1(DBG_PTS, "%d measurements, %d ok, %d not found, %d differ",
  161. this->list->get_count(this->list),
  162. count_ok, count_not_found, count_differ);
  163. return TRUE;
  164. }
  165. METHOD(pts_file_meas_t, verify, bool,
  166. private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir)
  167. {
  168. int fid, fid_last = 0;
  169. char *filename;
  170. uint8_t measurement_buf[HASH_SIZE_SHA512], *hex_meas_buf;
  171. chunk_t measurement, hex_meas;
  172. entry_t *entry;
  173. enumerator_t *enumerator = NULL;
  174. bool found = FALSE, match = FALSE, success = TRUE;
  175. while (e_hash->enumerate(e_hash, &fid, &filename, &hex_meas_buf))
  176. {
  177. if (fid != fid_last)
  178. {
  179. if (found && !match)
  180. {
  181. /* no matching hash value found for last filename */
  182. success = FALSE;
  183. DBG1(DBG_PTS, " %#B for '%s' is incorrect",
  184. &entry->measurement, entry->filename);
  185. enumerator->destroy(enumerator);
  186. }
  187. /* get a new filename from the database */
  188. found = FALSE;
  189. match = FALSE;
  190. fid_last = fid;
  191. /**
  192. * check if we find an entry for this filename
  193. * in the PTS measurement list
  194. */
  195. enumerator = this->list->create_enumerator(this->list);
  196. while (enumerator->enumerate(enumerator, &entry))
  197. {
  198. if (!is_dir || streq(filename, entry->filename))
  199. {
  200. found = TRUE;
  201. break;
  202. }
  203. }
  204. /* no PTS measurement returned for this filename */
  205. if (!found)
  206. {
  207. success = FALSE;
  208. DBG1(DBG_PTS, " no measurement found for '%s'", filename);
  209. enumerator->destroy(enumerator);
  210. }
  211. }
  212. if (found && !match)
  213. {
  214. hex_meas = chunk_from_str(hex_meas_buf);
  215. measurement = chunk_from_hex(hex_meas, measurement_buf);
  216. if (chunk_equals(measurement, entry->measurement))
  217. {
  218. match = TRUE;
  219. DBG2(DBG_PTS, " %#B for '%s' is ok",
  220. &entry->measurement, entry->filename);
  221. enumerator->destroy(enumerator);
  222. }
  223. }
  224. }
  225. if (found && !match)
  226. {
  227. /* no matching hash value found for the very last filename */
  228. success = FALSE;
  229. DBG1(DBG_PTS, " %#B for '%s' is incorrect",
  230. &entry->measurement, entry->filename);
  231. enumerator->destroy(enumerator);
  232. }
  233. return success;
  234. }
  235. METHOD(pts_file_meas_t, destroy, void,
  236. private_pts_file_meas_t *this)
  237. {
  238. this->list->destroy_function(this->list, (void *)free_entry);
  239. free(this);
  240. }
  241. /**
  242. * See header
  243. */
  244. pts_file_meas_t *pts_file_meas_create(uint16_t request_id)
  245. {
  246. private_pts_file_meas_t *this;
  247. INIT(this,
  248. .public = {
  249. .get_request_id = _get_request_id,
  250. .get_file_count = _get_file_count,
  251. .add = _add,
  252. .create_enumerator = _create_enumerator,
  253. .check = _check,
  254. .verify = _verify,
  255. .destroy = _destroy,
  256. },
  257. .request_id = request_id,
  258. .list = linked_list_create(),
  259. );
  260. return &this->public;
  261. }
  262. /**
  263. * Hash a file with a given absolute pathname
  264. */
  265. static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
  266. {
  267. u_char buffer[4096];
  268. size_t bytes_read;
  269. bool success = TRUE;
  270. FILE *file;
  271. file = fopen(pathname, "rb");
  272. if (!file)
  273. {
  274. DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname,
  275. strerror(errno));
  276. return FALSE;
  277. }
  278. while (TRUE)
  279. {
  280. bytes_read = fread(buffer, 1, sizeof(buffer), file);
  281. if (bytes_read > 0)
  282. {
  283. if (!hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL))
  284. {
  285. DBG1(DBG_PTS, " hasher increment error");
  286. success = FALSE;
  287. break;
  288. }
  289. }
  290. else
  291. {
  292. if (!hasher->get_hash(hasher, chunk_empty, hash))
  293. {
  294. DBG1(DBG_PTS, " hasher finalize error");
  295. success = FALSE;
  296. }
  297. break;
  298. }
  299. }
  300. fclose(file);
  301. return success;
  302. }
  303. /**
  304. * See header
  305. */
  306. pts_file_meas_t *pts_file_meas_create_from_path(uint16_t request_id,
  307. char *pathname, bool is_dir, bool use_rel_name,
  308. pts_meas_algorithms_t alg)
  309. {
  310. private_pts_file_meas_t *this;
  311. hash_algorithm_t hash_alg;
  312. hasher_t *hasher;
  313. u_char hash[HASH_SIZE_SHA384];
  314. chunk_t measurement;
  315. char* filename;
  316. bool success = TRUE;
  317. /* Create a hasher and a hash measurement buffer */
  318. hash_alg = pts_meas_algo_to_hash(alg);
  319. hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
  320. if (!hasher)
  321. {
  322. DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg);
  323. return NULL;
  324. }
  325. measurement = chunk_create(hash, hasher->get_hash_size(hasher));
  326. this = (private_pts_file_meas_t*)pts_file_meas_create(request_id);
  327. if (is_dir)
  328. {
  329. enumerator_t *enumerator;
  330. char *rel_name, *abs_name;
  331. struct stat st;
  332. enumerator = enumerator_create_directory(pathname);
  333. if (!enumerator)
  334. {
  335. DBG1(DBG_PTS, " directory '%s' can not be opened, %s", pathname,
  336. strerror(errno));
  337. success = FALSE;
  338. goto end;
  339. }
  340. while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
  341. {
  342. /* measure regular files only */
  343. if (S_ISREG(st.st_mode) && *rel_name != '.')
  344. {
  345. if (!hash_file(hasher, abs_name, hash))
  346. {
  347. continue;
  348. }
  349. filename = use_rel_name ? rel_name : abs_name;
  350. DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
  351. add(this, filename, measurement);
  352. }
  353. }
  354. enumerator->destroy(enumerator);
  355. }
  356. else
  357. {
  358. if (!hash_file(hasher, pathname, hash))
  359. {
  360. success = FALSE;
  361. goto end;
  362. }
  363. filename = use_rel_name ? path_basename(pathname) : strdup(pathname);
  364. DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
  365. add(this, filename, measurement);
  366. free(filename);
  367. }
  368. end:
  369. hasher->destroy(hasher);
  370. if (success)
  371. {
  372. return &this->public;
  373. }
  374. else
  375. {
  376. destroy(this);
  377. return NULL;
  378. }
  379. }