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