123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- /*
- * Copyright (C) 2011 Sansar Choinyambuu
- * Copyright (C) 2014 Andreas Steffen
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
- #include "pts_file_meas.h"
- #include <collections/linked_list.h>
- #include <utils/debug.h>
- #include <sys/stat.h>
- #include <libgen.h>
- #include <errno.h>
- typedef struct private_pts_file_meas_t private_pts_file_meas_t;
- /**
- * Private data of a pts_file_meas_t object.
- *
- */
- struct private_pts_file_meas_t {
- /**
- * Public pts_file_meas_t interface.
- */
- pts_file_meas_t public;
- /**
- * ID of PTS File Measurement Request
- */
- uint16_t request_id;
- /**
- * List of File Measurements
- */
- linked_list_t *list;
- };
- typedef struct entry_t entry_t;
- /**
- * PTS File Measurement entry
- */
- struct entry_t {
- char *filename;
- chunk_t measurement;
- };
- /**
- * Free an entry_t object
- */
- static void free_entry(entry_t *entry)
- {
- if (entry)
- {
- free(entry->filename);
- free(entry->measurement.ptr);
- free(entry);
- }
- }
- METHOD(pts_file_meas_t, get_request_id, uint16_t,
- private_pts_file_meas_t *this)
- {
- return this->request_id;
- }
- METHOD(pts_file_meas_t, get_file_count, int,
- private_pts_file_meas_t *this)
- {
- return this->list->get_count(this->list);
- }
- METHOD(pts_file_meas_t, add, void,
- private_pts_file_meas_t *this, char *filename, chunk_t measurement)
- {
- entry_t *entry;
- entry = malloc_thing(entry_t);
- entry->filename = strdup(filename);
- entry->measurement = chunk_clone(measurement);
- this->list->insert_last(this->list, entry);
- }
- CALLBACK(entry_filter, bool,
- void *null, enumerator_t *orig, va_list args)
- {
- entry_t *entry;
- chunk_t *measurement;
- char **filename;
- VA_ARGS_VGET(args, filename, measurement);
- if (orig->enumerate(orig, &entry))
- {
- *filename = entry->filename;
- *measurement = entry->measurement;
- return TRUE;
- }
- return FALSE;
- }
- METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
- private_pts_file_meas_t *this)
- {
- return enumerator_create_filter(this->list->create_enumerator(this->list),
- entry_filter, NULL, NULL);
- }
- METHOD(pts_file_meas_t, check, bool,
- private_pts_file_meas_t *this, pts_database_t *pts_db, int pid,
- pts_meas_algorithms_t algo)
- {
- enumerator_t *enumerator, *e;
- entry_t *entry;
- chunk_t hash;
- int count_ok = 0, count_not_found = 0, count_differ = 0;
- status_t status;
- enumerator = this->list->create_enumerator(this->list);
- while (enumerator->enumerate(enumerator, &entry))
- {
- status = NOT_FOUND;
- e = pts_db->create_file_meas_enumerator(pts_db, pid, algo,
- entry->filename);
- if (e)
- {
- while (e->enumerate(e, &hash))
- {
- if (chunk_equals(entry->measurement, hash))
- {
- status = SUCCESS;
- break;
- }
- else
- {
- status = VERIFY_ERROR;
- }
- }
- e->destroy(e);
- }
- else
- {
- status = FAILED;
- }
- switch (status)
- {
- case SUCCESS:
- DBG3(DBG_PTS, " %#B for '%s' is ok", &entry->measurement,
- entry->filename);
- count_ok++;
- break;
- case NOT_FOUND:
- DBG2(DBG_PTS, " %#B for '%s' not found", &entry->measurement,
- entry->filename);
- count_not_found++;
- break;
- case VERIFY_ERROR:
- DBG1(DBG_PTS, " %#B for '%s' differs", &entry->measurement,
- entry->filename);
- count_differ++;
- break;
- case FAILED:
- default:
- DBG1(DBG_PTS, " %#B for '%s' failed", &entry->measurement,
- entry->filename);
- }
- }
- enumerator->destroy(enumerator);
- DBG1(DBG_PTS, "%d measurements, %d ok, %d not found, %d differ",
- this->list->get_count(this->list),
- count_ok, count_not_found, count_differ);
- return TRUE;
- }
- METHOD(pts_file_meas_t, verify, bool,
- private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir)
- {
- int fid, fid_last = 0;
- char *filename;
- uint8_t measurement_buf[HASH_SIZE_SHA512], *hex_meas_buf;
- chunk_t measurement, hex_meas;
- entry_t *entry;
- enumerator_t *enumerator = NULL;
- bool found = FALSE, match = FALSE, success = TRUE;
- while (e_hash->enumerate(e_hash, &fid, &filename, &hex_meas_buf))
- {
- if (fid != fid_last)
- {
- if (found && !match)
- {
- /* no matching hash value found for last filename */
- success = FALSE;
- DBG1(DBG_PTS, " %#B for '%s' is incorrect",
- &entry->measurement, entry->filename);
- enumerator->destroy(enumerator);
- }
- /* get a new filename from the database */
- found = FALSE;
- match = FALSE;
- fid_last = fid;
- /**
- * check if we find an entry for this filename
- * in the PTS measurement list
- */
- enumerator = this->list->create_enumerator(this->list);
- while (enumerator->enumerate(enumerator, &entry))
- {
- if (!is_dir || streq(filename, entry->filename))
- {
- found = TRUE;
- break;
- }
- }
- /* no PTS measurement returned for this filename */
- if (!found)
- {
- success = FALSE;
- DBG1(DBG_PTS, " no measurement found for '%s'", filename);
- enumerator->destroy(enumerator);
- }
- }
- if (found && !match)
- {
- hex_meas = chunk_from_str(hex_meas_buf);
- measurement = chunk_from_hex(hex_meas, measurement_buf);
- if (chunk_equals(measurement, entry->measurement))
- {
- match = TRUE;
- DBG2(DBG_PTS, " %#B for '%s' is ok",
- &entry->measurement, entry->filename);
- enumerator->destroy(enumerator);
- }
- }
- }
- if (found && !match)
- {
- /* no matching hash value found for the very last filename */
- success = FALSE;
- DBG1(DBG_PTS, " %#B for '%s' is incorrect",
- &entry->measurement, entry->filename);
- enumerator->destroy(enumerator);
- }
- return success;
- }
- METHOD(pts_file_meas_t, destroy, void,
- private_pts_file_meas_t *this)
- {
- this->list->destroy_function(this->list, (void *)free_entry);
- free(this);
- }
- /**
- * See header
- */
- pts_file_meas_t *pts_file_meas_create(uint16_t request_id)
- {
- private_pts_file_meas_t *this;
- INIT(this,
- .public = {
- .get_request_id = _get_request_id,
- .get_file_count = _get_file_count,
- .add = _add,
- .create_enumerator = _create_enumerator,
- .check = _check,
- .verify = _verify,
- .destroy = _destroy,
- },
- .request_id = request_id,
- .list = linked_list_create(),
- );
- return &this->public;
- }
- /**
- * Hash a file with a given absolute pathname
- */
- static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
- {
- u_char buffer[4096];
- size_t bytes_read;
- bool success = TRUE;
- FILE *file;
- file = fopen(pathname, "rb");
- if (!file)
- {
- DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname,
- strerror(errno));
- return FALSE;
- }
- while (TRUE)
- {
- bytes_read = fread(buffer, 1, sizeof(buffer), file);
- if (bytes_read > 0)
- {
- if (!hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL))
- {
- DBG1(DBG_PTS, " hasher increment error");
- success = FALSE;
- break;
- }
- }
- else
- {
- if (!hasher->get_hash(hasher, chunk_empty, hash))
- {
- DBG1(DBG_PTS, " hasher finalize error");
- success = FALSE;
- }
- break;
- }
- }
- fclose(file);
- return success;
- }
- /**
- * See header
- */
- pts_file_meas_t *pts_file_meas_create_from_path(uint16_t request_id,
- char *pathname, bool is_dir, bool use_rel_name,
- pts_meas_algorithms_t alg)
- {
- private_pts_file_meas_t *this;
- hash_algorithm_t hash_alg;
- hasher_t *hasher;
- u_char hash[HASH_SIZE_SHA384];
- chunk_t measurement;
- char* filename;
- bool success = TRUE;
- /* Create a hasher and a hash measurement buffer */
- hash_alg = pts_meas_algo_to_hash(alg);
- hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
- if (!hasher)
- {
- DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg);
- return NULL;
- }
- measurement = chunk_create(hash, hasher->get_hash_size(hasher));
- this = (private_pts_file_meas_t*)pts_file_meas_create(request_id);
- if (is_dir)
- {
- enumerator_t *enumerator;
- char *rel_name, *abs_name;
- struct stat st;
- enumerator = enumerator_create_directory(pathname);
- if (!enumerator)
- {
- DBG1(DBG_PTS, " directory '%s' can not be opened, %s", pathname,
- strerror(errno));
- success = FALSE;
- goto end;
- }
- while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
- {
- /* measure regular files only */
- if (S_ISREG(st.st_mode) && *rel_name != '.')
- {
- if (!hash_file(hasher, abs_name, hash))
- {
- continue;
- }
- filename = use_rel_name ? rel_name : abs_name;
- DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
- add(this, filename, measurement);
- }
- }
- enumerator->destroy(enumerator);
- }
- else
- {
- if (!hash_file(hasher, pathname, hash))
- {
- success = FALSE;
- goto end;
- }
- filename = use_rel_name ? path_basename(pathname) : strdup(pathname);
- DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
- add(this, filename, measurement);
- free(filename);
- }
- end:
- hasher->destroy(hasher);
- if (success)
- {
- return &this->public;
- }
- else
- {
- destroy(this);
- return NULL;
- }
- }
|