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