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