]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/file.c
digests: Split off into a new set of files
[people/ms/pakfire.git] / src / libpakfire / file.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2014 Pakfire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <libgen.h>
23 #include <linux/limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <time.h>
29
30 #include <archive_entry.h>
31 #include <openssl/err.h>
32 #include <openssl/evp.h>
33
34 #include <pakfire/constants.h>
35 #include <pakfire/digest.h>
36 #include <pakfire/file.h>
37 #include <pakfire/logging.h>
38 #include <pakfire/pakfire.h>
39 #include <pakfire/private.h>
40 #include <pakfire/string.h>
41 #include <pakfire/util.h>
42
43 enum pakfire_file_verification_status {
44 PAKFIRE_FILE_NOENT = (1 << 0),
45 PAKFIRE_FILE_TYPE_CHANGED = (1 << 1),
46 PAKFIRE_FILE_PERMISSIONS_CHANGED = (1 << 2),
47 PAKFIRE_FILE_DEV_CHANGED = (1 << 3),
48 PAKFIRE_FILE_SIZE_CHANGED = (1 << 4),
49 PAKFIRE_FILE_OWNER_CHANGED = (1 << 5),
50 PAKFIRE_FILE_GROUP_CHANGED = (1 << 6),
51 PAKFIRE_FILE_CTIME_CHANGED = (1 << 7),
52 PAKFIRE_FILE_MTIME_CHANGED = (1 << 8),
53 PAKFIRE_FILE_PAYLOAD_CHANGED = (1 << 9),
54 };
55
56 struct pakfire_file {
57 struct pakfire* pakfire;
58 int nrefs;
59
60 // The relative path
61 char path[PATH_MAX];
62
63 // The absolute path in the file system
64 char abspath[PATH_MAX];
65
66 // File Ownership
67 char user[LOGIN_NAME_MAX];
68 char group[LOGIN_NAME_MAX];
69
70 // Stat
71 struct stat st;
72
73 // Link destinations
74 char hardlink[PATH_MAX];
75 char symlink[PATH_MAX];
76
77 // Digests
78 struct pakfire_digests digests;
79
80 // Verification Status
81 int verify_status;
82
83 #warning TODO capabilities, config, data
84 // capabilities
85 //int is_configfile;
86 //int is_datafile;
87 };
88
89 /*
90 Returns one if the digest is not all zeros.
91 */
92 #define pakfire_file_has_digest(digest) __pakfire_file_has_digest(digest, sizeof(digest))
93
94 static int __pakfire_file_has_digest(const unsigned char* digest, const size_t length) {
95 for (unsigned int i = 0; i < length; i++) {
96 if (digest[i])
97 return 1;
98 }
99
100 return 0;
101 }
102
103 static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) {
104 const char* attr = NULL;
105 const void* value = NULL;
106 size_t size = 0;
107 int r = 0;
108
109 // Set abspath
110 r = pakfire_file_set_abspath(file, archive_entry_sourcepath(entry));
111 if (r) {
112 ERROR(file->pakfire, "Could not set abspath: %m\n");
113 goto ERROR;
114 }
115
116 // Set path
117 const char* path = archive_entry_pathname(entry);
118 if (path) {
119 // Strip any leading dots from paths
120 if (pakfire_string_startswith(path, "./"))
121 path++;
122
123 r = pakfire_file_set_path(file, path);
124 if (r) {
125 ERROR(file->pakfire, "Could not set path: %m\n");
126 goto ERROR;
127 }
128 }
129
130 // Set links
131 pakfire_file_set_hardlink(file, archive_entry_hardlink(entry));
132 pakfire_file_set_symlink(file, archive_entry_symlink(entry));
133
134 // Set size
135 pakfire_file_set_size(file, archive_entry_size(entry));
136
137 // Set mode
138 pakfire_file_set_mode(file, archive_entry_mode(entry));
139
140 // Set dev type
141 if (archive_entry_dev_is_set(entry))
142 pakfire_file_set_dev(file, archive_entry_dev(entry));
143
144 // Set user
145 pakfire_file_set_user(file, archive_entry_uname(entry));
146
147 // Set group
148 pakfire_file_set_group(file, archive_entry_gname(entry));
149
150 // Set times
151 pakfire_file_set_ctime(file, archive_entry_ctime(entry));
152 pakfire_file_set_mtime(file, archive_entry_mtime(entry));
153
154 // Read any extended attributes
155 while (archive_entry_xattr_next(entry, &attr, &value, &size) == ARCHIVE_OK) {
156 // Digest: SHA-512
157 if (strcmp(attr, "PAKFIRE.digests.sha512") == 0) {
158 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA512, value, size);
159 if (r)
160 goto ERROR;
161
162 // Digest: SHA-256
163 } else if (strcmp(attr, "PAKFIRE.digests.sha256") == 0) {
164 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA256, value, size);
165 if (r)
166 goto ERROR;
167
168 } else {
169 DEBUG(file->pakfire, "Received an unknown extended attribute: %s\n", attr);
170 }
171 }
172
173 ERROR:
174 return r;
175 }
176
177 PAKFIRE_EXPORT int pakfire_file_create(struct pakfire_file** file, struct pakfire* pakfire) {
178 struct pakfire_file* f = calloc(1, sizeof(*f));
179 if (!f)
180 return 1;
181
182 // Store reference to Pakfire
183 f->pakfire = pakfire_ref(pakfire);
184
185 // Initialize reference counter
186 f->nrefs = 1;
187
188 *file = f;
189 return 0;
190 }
191
192 int pakfire_file_create_from_path(struct pakfire_file** file,
193 struct pakfire* pakfire, const char* path) {
194 struct archive* reader = NULL;
195 struct archive_entry* entry = NULL;
196 int r = 1;
197
198 // Allocate a reader
199 reader = pakfire_make_archive_disk_reader(pakfire, 0);
200 if (!reader)
201 goto ERROR;
202
203 // Allocate a new archive entry
204 entry = archive_entry_new();
205 if (!entry)
206 goto ERROR;
207
208 // Set source path
209 archive_entry_copy_sourcepath(entry, path);
210
211 // Read all file attributes from disk
212 r = archive_read_disk_entry_from_file(reader, entry, -1, NULL);
213 if (r) {
214 ERROR(pakfire, "Could not read from %s: %m\n", path);
215 goto ERROR;
216 }
217
218 // Create file
219 r = pakfire_file_create_from_archive_entry(file, pakfire, entry);
220 if (r)
221 goto ERROR;
222
223 ERROR:
224 if (r)
225 ERROR(pakfire, "Could not create file from path %s: %m\n", path);
226 if (entry)
227 archive_entry_free(entry);
228 if (reader)
229 archive_read_free(reader);
230
231 return r;
232 }
233
234 int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire,
235 struct archive_entry* entry) {
236 int r = pakfire_file_create(file, pakfire);
237 if (r)
238 return r;
239
240 // Copy archive entry
241 r = pakfire_file_from_archive_entry(*file, entry);
242 if (r)
243 goto ERROR;
244
245 return 0;
246
247 ERROR:
248 pakfire_file_unref(*file);
249 *file = NULL;
250
251 return r;
252 }
253
254 struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file) {
255 struct archive_entry* entry = archive_entry_new();
256 if (!entry) {
257 ERROR(file->pakfire, "Could not allocate archive entry: %m\n");
258 return NULL;
259 }
260
261 // Set path
262 archive_entry_copy_pathname(entry, pakfire_file_get_path(file));
263
264 // Set source path
265 archive_entry_copy_sourcepath(entry, file->abspath);
266
267 // Set links
268 if (*file->hardlink)
269 archive_entry_set_hardlink(entry, file->hardlink);
270 if (*file->symlink)
271 archive_entry_set_symlink(entry, file->symlink);
272
273 // Set size
274 archive_entry_set_size(entry, pakfire_file_get_size(file));
275
276 // Set mode
277 archive_entry_set_mode(entry, pakfire_file_get_mode(file));
278
279 // Set user
280 archive_entry_set_uname(entry, pakfire_file_get_user(file));
281
282 // Set group
283 archive_entry_set_gname(entry, pakfire_file_get_group(file));
284
285 // Set times
286 archive_entry_set_ctime(entry, pakfire_file_get_ctime(file), 0);
287 archive_entry_set_mtime(entry, pakfire_file_get_mtime(file), 0);
288
289 // Copy digests
290
291 // SHA-512
292 if (pakfire_file_has_digest(file->digests.sha512))
293 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha512",
294 file->digests.sha512, sizeof(file->digests.sha512));
295
296 // SHA-256
297 if (pakfire_file_has_digest(file->digests.sha256))
298 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha256",
299 file->digests.sha256, sizeof(file->digests.sha256));
300
301 return entry;
302 }
303
304 static void pakfire_file_free(struct pakfire_file* file) {
305 pakfire_unref(file->pakfire);
306 free(file);
307 }
308
309 PAKFIRE_EXPORT struct pakfire_file* pakfire_file_ref(struct pakfire_file* file) {
310 file->nrefs++;
311
312 return file;
313 }
314
315 PAKFIRE_EXPORT struct pakfire_file* pakfire_file_unref(struct pakfire_file* file) {
316 if (--file->nrefs > 0)
317 return file;
318
319 pakfire_file_free(file);
320 return NULL;
321 }
322
323 PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_file* file2) {
324 const char* path1 = pakfire_file_get_path(file1);
325 const char* path2 = pakfire_file_get_path(file2);
326
327 return strcmp(path1, path2);
328 }
329
330 const char* pakfire_file_get_abspath(struct pakfire_file* file) {
331 return file->abspath;
332 }
333
334 int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) {
335 // Check if path is set and absolute
336 if (!path || *path != '/') {
337 errno = EINVAL;
338 return 1;
339 }
340
341 return pakfire_string_set(file->abspath, path);
342 }
343
344 PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) {
345 return file->path;
346 }
347
348 PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) {
349 int r;
350
351 // Check if path is set and absolute
352 if (!path || *path != '/') {
353 errno = EINVAL;
354 return 1;
355 }
356
357 // Store path
358 r = pakfire_string_set(file->path, path);
359 if (r)
360 return r;
361
362 // Set abspath if it isn't set, yet
363 if (!*file->abspath) {
364 r = pakfire_path(file->pakfire, file->abspath, "%s", path);
365 if (r)
366 return r;
367 }
368
369 return r;
370 }
371
372 PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) {
373 if (!*file->hardlink)
374 return NULL;
375
376 return file->hardlink;
377 }
378
379 PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) {
380 if (!link || !*link)
381 *file->hardlink = '\0';
382 else
383 pakfire_string_set(file->hardlink, link);
384 }
385
386 PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) {
387 if (!*file->symlink)
388 return NULL;
389
390 return file->symlink;
391 }
392
393 PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) {
394 if (!link || !*link)
395 *file->hardlink = '\0';
396 else
397 pakfire_string_set(file->symlink, link);
398 }
399
400 PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) {
401 return file->st.st_mode & S_IFMT;
402 }
403
404 PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) {
405 return file->st.st_size;
406 }
407
408 PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) {
409 file->st.st_size = size;
410 }
411
412 PAKFIRE_EXPORT const char* pakfire_file_get_user(struct pakfire_file* file) {
413 return file->user;
414 }
415
416 PAKFIRE_EXPORT int pakfire_file_set_user(struct pakfire_file* file, const char* user) {
417 return pakfire_string_set(file->user, user);
418 }
419
420 PAKFIRE_EXPORT const char* pakfire_file_get_group(struct pakfire_file* file) {
421 return file->group;
422 }
423
424 PAKFIRE_EXPORT int pakfire_file_set_group(struct pakfire_file* file, const char* group) {
425 return pakfire_string_set(file->group, group);
426 }
427
428 PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) {
429 return file->st.st_mode;
430 }
431
432 PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) {
433 file->st.st_mode = mode;
434 }
435
436 PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) {
437 return file->st.st_mode & ~AE_IFMT;
438 }
439
440 PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) {
441 // Clear any previous permissions
442 file->st.st_mode &= S_IFMT;
443
444 // Set new bits (with format cleared)
445 file->st.st_mode |= ~S_IFMT & perms;
446 }
447
448 PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) {
449 return file->st.st_dev;
450 }
451
452 PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, dev_t dev) {
453 file->st.st_dev = dev;
454 }
455
456 PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) {
457 return file->st.st_ctime;
458 }
459
460 PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) {
461 file->st.st_ctime = time;
462 }
463
464 PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) {
465 return file->st.st_mtime;
466 }
467
468 PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) {
469 file->st.st_mtime = time;
470 }
471
472 PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest(
473 struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) {
474
475 switch (type) {
476 case PAKFIRE_DIGEST_SHA512:
477 if (!pakfire_file_has_digest(file->digests.sha512))
478 return NULL;
479
480 if (length)
481 *length = sizeof(file->digests.sha512);
482
483 return file->digests.sha512;
484
485 case PAKFIRE_DIGEST_SHA256:
486 if (!pakfire_file_has_digest(file->digests.sha256))
487 return NULL;
488
489 if (length)
490 *length = sizeof(file->digests.sha256);
491
492 return file->digests.sha256;
493 }
494
495 return NULL;
496 }
497
498 PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file,
499 const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
500 if (!digest) {
501 errno = EINVAL;
502 return 1;
503 }
504
505 // Check buffer length
506 if (pakfire_digest_length(type) != length) {
507 ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length);
508 errno = ENOMSG;
509 return 1;
510 }
511
512 // Store the digest
513 switch (type) {
514 case PAKFIRE_DIGEST_SHA512:
515 memcpy(file->digests.sha512, digest, sizeof(file->digests.sha512));
516 break;
517
518 case PAKFIRE_DIGEST_SHA256:
519 memcpy(file->digests.sha256, digest, sizeof(file->digests.sha256));
520 break;
521 }
522
523 return 0;
524 }
525
526 PAKFIRE_EXPORT char* pakfire_file_get_hexdigest(
527 struct pakfire_file* file, const enum pakfire_digest_types type) {
528 const unsigned char* digest = NULL;
529 size_t length = 0;
530
531 // Fetch the digest
532 digest = pakfire_file_get_digest(file, type, &length);
533 if (!digest)
534 return NULL;
535
536 return __pakfire_hexlify(digest, length);
537 }
538
539 static int pakfire_file_levels(struct pakfire_file* file) {
540 if (!*file->path)
541 return 0;
542
543 int levels = 0;
544
545 for (char* p = file->path; *p; p++) {
546 if (*p == '/')
547 levels++;
548 }
549
550 return levels;
551 }
552
553 FILE* pakfire_file_open(struct pakfire_file* file) {
554 FILE* f = fopen(file->abspath, "r");
555 if (!f)
556 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
557
558 return f;
559 }
560
561 int pakfire_file_remove(struct pakfire_file* file) {
562 if (!*file->abspath) {
563 errno = EINVAL;
564 return 1;
565 }
566
567 DEBUG(file->pakfire, "Removing %s...\n", file->path);
568
569 int r = remove(file->abspath);
570 if (r) {
571 switch (errno) {
572 // Ignore when we could not remove directories
573 case ENOTEMPTY:
574 return 0;
575
576 // Ignore if the file didn't exist
577 case ENOENT:
578 return 0;
579
580 default:
581 break;
582 }
583
584 ERROR(file->pakfire, "Could not remove %s (%s): %m\n", file->path, file->abspath);
585 }
586
587 return r;
588 }
589
590 /*
591 This function tries to remove the file after it has been packaged.
592
593 It will try to delete any parent directories as well and ignore if directories
594 cannot be deleted because they might contain other files
595 */
596 int pakfire_file_cleanup(struct pakfire_file* file) {
597 char path[PATH_MAX];
598
599 // Try removing the file
600 int r = pakfire_file_remove(file);
601 if (r)
602 return r;
603
604 // Create a working copy of abspath
605 r = pakfire_string_set(path, file->abspath);
606 if (r)
607 return r;
608
609 // See how many levels this file has
610 int levels = pakfire_file_levels(file);
611
612 // Walk all the way up and remove all parent directories if possible
613 while (--levels) {
614 dirname(path);
615
616 // Break if path is suddenly empty
617 if (!*path)
618 break;
619
620 r = rmdir(path);
621 if (r) {
622 if (errno == ENOTEMPTY)
623 return 0;
624
625 return r;
626 }
627 }
628
629 return 0;
630 }
631
632 static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat* st) {
633 const mode_t type = pakfire_file_get_type(file);
634
635 // Did the type change?
636 if (type != (st->st_mode & S_IFMT)) {
637 file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED;
638
639 DEBUG(file->pakfire, "%s: File Type changed\n", file->path);
640 }
641
642 const mode_t perms = pakfire_file_get_perms(file);
643
644 // Check permissions
645 if (perms != (st->st_mode & 0777)) {
646 file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED;
647
648 DEBUG(file->pakfire, "%s: Permissions changed\n", file->path);
649 }
650
651 // Check if device node changed
652 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
653 const dev_t dev = pakfire_file_get_dev(file);
654
655 if (dev != st->st_dev) {
656 file->verify_status |= PAKFIRE_FILE_DEV_CHANGED;
657
658 DEBUG(file->pakfire, "%s: Device Node changed\n", file->path);
659 }
660 }
661
662 return 0;
663 }
664
665 static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) {
666 // Nothing to do if size matches
667 if (file->st.st_size == st->st_size)
668 return 0;
669
670 // Size differs
671 file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED;
672
673 DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
674 file->path, file->st.st_size, st->st_size);
675
676 return 0;
677 }
678
679 static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct stat* st) {
680 // Fetch UID/GID
681 #if 0
682 const uid_t uid = pakfire_unmap_id(file->pakfire, st->st_uid);
683 const gid_t gid = pakfire_unmap_id(file->pakfire, st->st_gid);
684 #else
685 const uid_t uid = st->st_uid;
686 const gid_t gid = st->st_gid;
687 #endif
688
689 // Fetch owner & group
690 struct passwd* owner = pakfire_getpwnam(file->pakfire, file->user);
691 struct group* group = pakfire_getgrnam(file->pakfire, file->group);
692
693 // Check if owner matches
694 if (!owner || owner->pw_uid != uid) {
695 file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED;
696
697 DEBUG(file->pakfire, "%s: Owner differs\n", file->path);
698 }
699
700 // Check if group matches
701 if (!group || group->gr_gid != gid) {
702 file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED;
703
704 DEBUG(file->pakfire, "%s: Group differs\n", file->path);
705 }
706
707 return 0;
708 }
709
710 static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) {
711 // Check creation time
712 if (file->st.st_ctime != st->st_ctime) {
713 file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED;
714
715 DEBUG(file->pakfire, "%s: Creation time changed\n", file->path);
716 }
717
718 // Check modification time
719 if (file->st.st_mtime != st->st_mtime) {
720 file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED;
721
722 DEBUG(file->pakfire, "%s: Modification time changed\n", file->path);
723 }
724
725 return 0;
726 }
727
728 static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) {
729 char buffer[PAKFIRE_BUFFER_SIZE];
730 FILE* f = NULL;
731 int r;
732
733 EVP_MD_CTX* sha512_ctx = NULL;
734 EVP_MD_CTX* sha256_ctx = NULL;
735
736 struct pakfire_digests computed_digests;
737
738 // Nothing to do for anything that isn't a regular file
739 if (!S_ISREG(st->st_mode))
740 return 0;
741
742 // Fast-path if size changed. The payload will have changed, too
743 if (file->verify_status & PAKFIRE_FILE_SIZE_CHANGED) {
744 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
745 return 0;
746 }
747
748 // Check if this file has any digests at all
749 if (!pakfire_file_has_digest(file->digests.sha512) &&
750 !pakfire_file_has_digest(file->digests.sha256)) {
751 ERROR(file->pakfire, "%s: No digests available\n", file->path);
752 return 0;
753 }
754
755 // Initialize context for SHA-512
756 sha512_ctx = EVP_MD_CTX_new();
757 if (!sha512_ctx) {
758 ERROR(file->pakfire, "Could not initialize OpenSSL context: %s\n",
759 ERR_error_string(ERR_get_error(), NULL));
760 r = 1;
761 goto ERROR;
762 }
763
764 // Setup SHA-512 digest
765 r = EVP_DigestInit_ex(sha512_ctx, EVP_sha512(), NULL);
766 if (r != 1) {
767 ERROR(file->pakfire, "Could not setup SHA-512 digest: %s\n",
768 ERR_error_string(ERR_get_error(), NULL));
769 r = 1;
770 goto ERROR;
771 }
772
773 // Initialize context for SHA-256
774 sha256_ctx = EVP_MD_CTX_new();
775 if (!sha256_ctx) {
776 ERROR(file->pakfire, "Could not initialize OpenSSL context: %s\n",
777 ERR_error_string(ERR_get_error(), NULL));
778 r = 1;
779 goto ERROR;
780 }
781
782 // Setup SHA-256 digest
783 r = EVP_DigestInit_ex(sha256_ctx, EVP_sha256(), NULL);
784 if (r != 1) {
785 ERROR(file->pakfire, "Could not setup SHA-256 digest: %s\n",
786 ERR_error_string(ERR_get_error(), NULL));
787 r = 1;
788 goto ERROR;
789 }
790
791 // Open the file
792 f = pakfire_file_open(file);
793 if (!f) {
794 ERROR(file->pakfire, "Could not open %s: %m\n", file->path);
795 goto ERROR;
796 }
797
798 // Read the file into the hash functions
799 while (!feof(f)) {
800 size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
801
802 // Raise any reading errors
803 if (ferror(f)) {
804 r = 1;
805 goto ERROR;
806 }
807
808 // SHA-512
809 r = EVP_DigestUpdate(sha512_ctx, buffer, bytes_read);
810 if (r != 1) {
811 ERROR(file->pakfire, "EVP_Digest_Update() failed: %s\n",
812 ERR_error_string(ERR_get_error(), NULL));
813 r = 1;
814 goto ERROR;
815 }
816
817 // SHA-256
818 r = EVP_DigestUpdate(sha256_ctx, buffer, bytes_read);
819 if (r != 1) {
820 ERROR(file->pakfire, "EVP_Digest_Update() failed: %s\n",
821 ERR_error_string(ERR_get_error(), NULL));
822 r = 1;
823 goto ERROR;
824 }
825 }
826
827 // Finalize SHA-512
828 r = EVP_DigestFinal_ex(sha512_ctx, computed_digests.sha512, NULL);
829 if (r != 1) {
830 ERROR(file->pakfire, "EVP_DigestFinal_ex() failed: %s\n",
831 ERR_error_string(ERR_get_error(), NULL));
832 r = 1;
833 goto ERROR;
834 }
835
836 // Finalize SHA-256
837 r = EVP_DigestFinal_ex(sha256_ctx, computed_digests.sha256, NULL);
838 if (r != 1) {
839 ERROR(file->pakfire, "EVP_DigestFinal_ex() failed: %s\n",
840 ERR_error_string(ERR_get_error(), NULL));
841 r = 1;
842 goto ERROR;
843 }
844
845 // Check SHA-512
846 r = CRYPTO_memcmp(computed_digests.sha512,
847 file->digests.sha512, sizeof(file->digests.sha512));
848 if (r) {
849 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
850
851 DEBUG(file->pakfire, "%s: SHA-512 digest does not match\n", file->path);
852 }
853
854 // Check SHA-256
855 r = CRYPTO_memcmp(computed_digests.sha256,
856 file->digests.sha256, sizeof(file->digests.sha256));
857 if (r) {
858 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
859
860 DEBUG(file->pakfire, "%s: SHA-256 digest does not match\n", file->path);
861 }
862
863 // Success
864 r = 0;
865
866 ERROR:
867 if (sha512_ctx)
868 EVP_MD_CTX_free(sha512_ctx);
869 if (sha256_ctx)
870 EVP_MD_CTX_free(sha256_ctx);
871 if (f)
872 fclose(f);
873
874 return r;
875 }
876
877 /*
878 Verify the file - i.e. does the metadata match what is on disk?
879 */
880 int pakfire_file_verify(struct pakfire_file* file, int* status) {
881 struct stat st;
882 int r;
883
884 DEBUG(file->pakfire, "Verifying %s...\n", file->path);
885
886 // stat() the file
887 r = lstat(file->abspath, &st);
888 if (r) {
889 // File does not exist
890 if (errno == ENOENT) {
891 file->verify_status |= PAKFIRE_FILE_NOENT;
892 return 1;
893 }
894
895 // Raise any other errors from stat()
896 return r;
897 }
898
899 // Verify mode
900 r = pakfire_file_verify_mode(file, &st);
901 if (r)
902 return r;
903
904 // Verify size
905 r = pakfire_file_verify_size(file, &st);
906 if (r)
907 return r;
908
909 // Verify ownership
910 r = pakfire_file_verify_ownership(file, &st);
911 if (r)
912 return r;
913
914 // Verify timestamps
915 r = pakfire_file_verify_timestamps(file, &st);
916 if (r)
917 return r;
918
919 // Verify payload
920 r = pakfire_file_verify_payload(file, &st);
921 if (r)
922 return r;
923
924 return 0;
925 }