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