]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/file.c
file: Unify fetching ELF sections
[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>
c064d9ec 22#include <fnmatch.h>
3fca5032 23#include <libgen.h>
293881bc 24#include <limits.h>
c98132d1 25#include <linux/limits.h>
221cc3ce
MT
26#include <stdlib.h>
27#include <string.h>
a09b95e0 28#include <sys/stat.h>
221cc3ce 29#include <sys/types.h>
221cc3ce
MT
30#include <time.h>
31
9a6e3e2d
MT
32#include <archive_entry.h>
33
df71dc60
MT
34#include <gelf.h>
35
221cc3ce 36#include <pakfire/constants.h>
c52e0148 37#include <pakfire/digest.h>
6d9dd7bc 38#include <pakfire/fhs.h>
221cc3ce 39#include <pakfire/file.h>
3fca5032 40#include <pakfire/logging.h>
883b3be9 41#include <pakfire/pakfire.h>
9f953e68 42#include <pakfire/private.h>
d973a13d 43#include <pakfire/string.h>
221cc3ce
MT
44#include <pakfire/util.h>
45
c0b051bb
MT
46enum pakfire_file_verification_status {
47 PAKFIRE_FILE_NOENT = (1 << 0),
9e09e361
MT
48 PAKFIRE_FILE_TYPE_CHANGED = (1 << 1),
49 PAKFIRE_FILE_PERMISSIONS_CHANGED = (1 << 2),
50 PAKFIRE_FILE_DEV_CHANGED = (1 << 3),
51 PAKFIRE_FILE_SIZE_CHANGED = (1 << 4),
52 PAKFIRE_FILE_OWNER_CHANGED = (1 << 5),
53 PAKFIRE_FILE_GROUP_CHANGED = (1 << 6),
0eeac4a5
MT
54 PAKFIRE_FILE_CTIME_CHANGED = (1 << 7),
55 PAKFIRE_FILE_MTIME_CHANGED = (1 << 8),
76011205 56 PAKFIRE_FILE_PAYLOAD_CHANGED = (1 << 9),
c0b051bb
MT
57};
58
5803b5f6 59struct pakfire_file {
ac4c607b 60 struct pakfire* pakfire;
5e9463ec 61 int nrefs;
221cc3ce 62
e8d3b985 63 // The relative path
3b9e3970 64 char path[PATH_MAX];
e8d3b985
MT
65
66 // The absolute path in the file system
0027da6f 67 char abspath[PATH_MAX];
221cc3ce 68
e8d3b985 69 // File Ownership
302e3253
MT
70 char uname[LOGIN_NAME_MAX];
71 char gname[LOGIN_NAME_MAX];
e8d3b985 72
a09b95e0
MT
73 // Stat
74 struct stat st;
d03fa9a3 75
2f3563b9
MT
76 // Flags
77 int flags;
78
59d8c727
MT
79 // Link destinations
80 char hardlink[PATH_MAX];
81 char symlink[PATH_MAX];
82
65131b30 83 // Digests
c52e0148 84 struct pakfire_digests digests;
5e9463ec 85
210aabe9
MT
86 // MIME Type
87 char mimetype[NAME_MAX];
88
71f6f465
MT
89 // Class
90 int class;
91
c0b051bb
MT
92 // Verification Status
93 int verify_status;
94
28886e21
MT
95 // File Issues
96 int issues;
97 int check_done:1;
f7f44921 98
2f3563b9 99 #warning TODO capabilities, data
5e9463ec 100 // capabilities
5e9463ec
MT
101 //int is_datafile;
102};
103
eb5daf3f 104static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) {
210aabe9 105 char* buffer = NULL;
49a39ad9 106 const char* path = NULL;
eb5daf3f
MT
107 const char* attr = NULL;
108 const void* value = NULL;
109 size_t size = 0;
110 int r = 0;
111
112 // Set abspath
49a39ad9
MT
113 path = archive_entry_sourcepath(entry);
114 if (path) {
115 // Make path absolute
116 path = pakfire_path_abspath(path);
004f0160
MT
117 if (!path) {
118 r = 1;
49a39ad9 119 goto ERROR;
004f0160 120 }
49a39ad9
MT
121
122 // Set
123 r = pakfire_file_set_abspath(file, path);
124 if (r) {
125 ERROR(file->pakfire, "Could not set abspath: %m\n");
126 goto ERROR;
127 }
eb5daf3f
MT
128 }
129
130 // Set path
49a39ad9 131 path = archive_entry_pathname(entry);
eb5daf3f 132 if (path) {
eb5daf3f
MT
133 r = pakfire_file_set_path(file, path);
134 if (r) {
135 ERROR(file->pakfire, "Could not set path: %m\n");
136 goto ERROR;
137 }
138 }
139
140 // Set links
141 pakfire_file_set_hardlink(file, archive_entry_hardlink(entry));
142 pakfire_file_set_symlink(file, archive_entry_symlink(entry));
143
f8733b31
MT
144 pakfire_file_set_nlink(file, archive_entry_nlink(entry));
145 pakfire_file_set_inode(file, archive_entry_ino64(entry));
146 pakfire_file_set_dev(file, archive_entry_dev(entry));
147
eb5daf3f
MT
148 // Set size
149 pakfire_file_set_size(file, archive_entry_size(entry));
150
151 // Set mode
152 pakfire_file_set_mode(file, archive_entry_mode(entry));
153
154 // Set dev type
155 if (archive_entry_dev_is_set(entry))
156 pakfire_file_set_dev(file, archive_entry_dev(entry));
157
302e3253
MT
158 // Set uname
159 pakfire_file_set_uname(file, archive_entry_uname(entry));
eb5daf3f 160
302e3253
MT
161 // Set gname
162 pakfire_file_set_gname(file, archive_entry_gname(entry));
eb5daf3f
MT
163
164 // Set times
165 pakfire_file_set_ctime(file, archive_entry_ctime(entry));
166 pakfire_file_set_mtime(file, archive_entry_mtime(entry));
167
210aabe9 168 // Reset iterating over extended attributes
471ccfc2
MT
169 archive_entry_xattr_reset(entry);
170
eb5daf3f
MT
171 // Read any extended attributes
172 while (archive_entry_xattr_next(entry, &attr, &value, &size) == ARCHIVE_OK) {
2f3563b9
MT
173 // Config Files
174 if (strcmp(attr, "PAKFIRE.config") == 0) {
175 r = pakfire_file_set_flags(file, PAKFIRE_FILE_CONFIG);
176 if (r)
177 goto ERROR;
178
210aabe9 179 // MIME type
2f3563b9 180 } else if (strcmp(attr, "PAKFIRE.mimetype") == 0) {
210aabe9
MT
181 // Copy the value into a NULL-terminated buffer
182 r = asprintf(&buffer, "%.*s", (int)size, (const char*)value);
183 if (r < 0)
184 goto ERROR;
185
186 // Assign the value
187 r = pakfire_file_set_mimetype(file, buffer);
188 if (r)
189 goto ERROR;
190
d98740de 191 // Digest: SHA-3-512
210aabe9 192 } else if (strcmp(attr, "PAKFIRE.digests.sha3_512") == 0) {
d98740de
MT
193 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_512, value, size);
194 if (r)
195 goto ERROR;
196
197 // Digest: SHA-3-256
198 } else if (strcmp(attr, "PAKFIRE.digests.sha3_256") == 0) {
199 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_256, value, size);
200 if (r)
201 goto ERROR;
202
f1e6c5df 203 // Digest: BLAKE2b512
d98740de 204 } else if (strcmp(attr, "PAKFIRE.digests.blake2b512") == 0) {
f1e6c5df
MT
205 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2B512, value, size);
206 if (r)
207 goto ERROR;
208
2822561a 209 // Digest: BLAKE2s256
f1e6c5df
MT
210 } else if (strcmp(attr, "PAKFIRE.digests.blake2s256") == 0) {
211 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2S256, value, size);
212 if (r)
213 goto ERROR;
214
4500ed0a
MT
215 // Digest: SHA-2-512
216 } else if (strcmp(attr, "PAKFIRE.digests.sha2_512") == 0) {
217 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_512, value, size);
eb5daf3f
MT
218 if (r)
219 goto ERROR;
220
4500ed0a
MT
221 // Digest: SHA-2-256
222 } else if (strcmp(attr, "PAKFIRE.digests.sha2_256") == 0) {
223 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_256, value, size);
eb5daf3f
MT
224 if (r)
225 goto ERROR;
226
227 } else {
228 DEBUG(file->pakfire, "Received an unknown extended attribute: %s\n", attr);
229 }
230 }
231
232ERROR:
210aabe9
MT
233 if (buffer)
234 free(buffer);
235
eb5daf3f
MT
236 return r;
237}
238
ac4c607b 239PAKFIRE_EXPORT int pakfire_file_create(struct pakfire_file** file, struct pakfire* pakfire) {
5803b5f6 240 struct pakfire_file* f = calloc(1, sizeof(*f));
5e9463ec 241 if (!f)
7403779a 242 return 1;
5e9463ec 243
e8d3b985 244 // Store reference to Pakfire
883b3be9 245 f->pakfire = pakfire_ref(pakfire);
e8d3b985
MT
246
247 // Initialize reference counter
5e9463ec
MT
248 f->nrefs = 1;
249
250 *file = f;
251 return 0;
d03fa9a3
MT
252}
253
61b0856b
MT
254int pakfire_file_create_from_path(struct pakfire_file** file,
255 struct pakfire* pakfire, const char* path) {
256 struct archive* reader = NULL;
257 struct archive_entry* entry = NULL;
258 int r = 1;
259
260 // Allocate a reader
261 reader = pakfire_make_archive_disk_reader(pakfire, 0);
262 if (!reader)
263 goto ERROR;
264
265 // Allocate a new archive entry
266 entry = archive_entry_new();
267 if (!entry)
268 goto ERROR;
269
270 // Set source path
271 archive_entry_copy_sourcepath(entry, path);
272
273 // Read all file attributes from disk
274 r = archive_read_disk_entry_from_file(reader, entry, -1, NULL);
275 if (r) {
276 ERROR(pakfire, "Could not read from %s: %m\n", path);
277 goto ERROR;
278 }
279
280 // Create file
281 r = pakfire_file_create_from_archive_entry(file, pakfire, entry);
282 if (r)
283 goto ERROR;
284
285ERROR:
286 if (r)
287 ERROR(pakfire, "Could not create file from path %s: %m\n", path);
288 if (entry)
289 archive_entry_free(entry);
290 if (reader)
291 archive_read_free(reader);
292
293 return r;
294}
295
ac4c607b 296int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire,
d0985e31
MT
297 struct archive_entry* entry) {
298 int r = pakfire_file_create(file, pakfire);
299 if (r)
300 return r;
301
302 // Copy archive entry
eb5daf3f 303 r = pakfire_file_from_archive_entry(*file, entry);
d0985e31
MT
304 if (r)
305 goto ERROR;
306
307 return 0;
308
309ERROR:
310 pakfire_file_unref(*file);
311 *file = NULL;
312
313 return r;
314}
315
49a39ad9 316struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) {
d7b476ef 317 const char* path = NULL;
d4b2ef2d 318 int r;
d7b476ef 319
5acd852e
MT
320 struct archive_entry* entry = archive_entry_new();
321 if (!entry) {
322 ERROR(file->pakfire, "Could not allocate archive entry: %m\n");
323 return NULL;
324 }
325
5acd852e
MT
326 // Set source path
327 archive_entry_copy_sourcepath(entry, file->abspath);
328
49a39ad9 329 // Set path
d7b476ef
MT
330 path = pakfire_file_get_path(file);
331 if (path && *path == '/') {
332 archive_entry_copy_pathname(entry, path + 1);
333 }
49a39ad9 334
5acd852e
MT
335 // Set links
336 if (*file->hardlink)
337 archive_entry_set_hardlink(entry, file->hardlink);
338 if (*file->symlink)
339 archive_entry_set_symlink(entry, file->symlink);
340
f8733b31
MT
341 archive_entry_set_nlink(entry, pakfire_file_get_nlink(file));
342 archive_entry_set_ino64(entry, pakfire_file_get_inode(file));
343 archive_entry_set_dev(entry, pakfire_file_get_dev(file));
344
5acd852e
MT
345 // Set size
346 archive_entry_set_size(entry, pakfire_file_get_size(file));
347
348 // Set mode
349 archive_entry_set_mode(entry, pakfire_file_get_mode(file));
350
302e3253
MT
351 // Set uname
352 archive_entry_set_uname(entry, pakfire_file_get_uname(file));
5acd852e 353
302e3253
MT
354 // Set gname
355 archive_entry_set_gname(entry, pakfire_file_get_gname(file));
5acd852e
MT
356
357 // Set times
358 archive_entry_set_ctime(entry, pakfire_file_get_ctime(file), 0);
359 archive_entry_set_mtime(entry, pakfire_file_get_mtime(file), 0);
360
2f3563b9
MT
361 // Flags
362 if (pakfire_file_has_flag(file, PAKFIRE_FILE_CONFIG)) {
363 archive_entry_xattr_add_entry(entry,
364 "PAKFIRE.config", "1", strlen("1"));
365 }
366
210aabe9
MT
367 // Set MIME type
368 const char* mimetype = pakfire_file_get_mimetype(file);
369 if (mimetype) {
370 archive_entry_xattr_add_entry(entry,
371 "PAKFIRE.mimetype", mimetype, strlen(mimetype));
372 }
373
d4b2ef2d
MT
374 // Compute any required file digests
375 r = pakfire_file_compute_digests(file, digest_types);
376 if (r)
377 goto ERROR;
378
399d14c2
MT
379 // Copy digests
380
d98740de 381 // SHA-3-512
045fa504
MT
382 if ((digest_types && PAKFIRE_DIGEST_SHA3_512)
383 && pakfire_digest_set(file->digests.sha3_512))
d98740de
MT
384 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_512",
385 file->digests.sha3_512, sizeof(file->digests.sha3_512));
386
387 // SHA-3-256
045fa504
MT
388 if ((digest_types && PAKFIRE_DIGEST_SHA3_256) &&
389 pakfire_digest_set(file->digests.sha3_256))
d98740de
MT
390 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_256",
391 file->digests.sha3_256, sizeof(file->digests.sha3_256));
392
f1e6c5df 393 // BLAKE2b512
045fa504
MT
394 if ((digest_types && PAKFIRE_DIGEST_BLAKE2B512) &&
395 pakfire_digest_set(file->digests.blake2b512))
f1e6c5df
MT
396 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2b512",
397 file->digests.blake2b512, sizeof(file->digests.blake2b512));
398
399 // BLAKE2s256
045fa504
MT
400 if ((digest_types && PAKFIRE_DIGEST_BLAKE2S256) &&
401 pakfire_digest_set(file->digests.blake2s256))
f1e6c5df
MT
402 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2s256",
403 file->digests.blake2s256, sizeof(file->digests.blake2s256));
404
4500ed0a 405 // SHA-2-512
045fa504
MT
406 if ((digest_types && PAKFIRE_DIGEST_SHA2_512) &&
407 pakfire_digest_set(file->digests.sha2_512))
4500ed0a
MT
408 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_512",
409 file->digests.sha2_512, sizeof(file->digests.sha2_512));
399d14c2 410
4500ed0a 411 // SHA-2-256
045fa504
MT
412 if ((digest_types && PAKFIRE_DIGEST_SHA2_512) &&
413 pakfire_digest_set(file->digests.sha2_256))
4500ed0a
MT
414 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_256",
415 file->digests.sha2_256, sizeof(file->digests.sha2_256));
5acd852e
MT
416
417 return entry;
d4b2ef2d
MT
418
419ERROR:
420 if (entry)
421 archive_entry_free(entry);
422
423 return NULL;
5acd852e
MT
424}
425
5803b5f6 426static void pakfire_file_free(struct pakfire_file* file) {
5e8dfbeb 427 pakfire_unref(file->pakfire);
f0d6233d 428 free(file);
221cc3ce
MT
429}
430
5803b5f6 431PAKFIRE_EXPORT struct pakfire_file* pakfire_file_ref(struct pakfire_file* file) {
5e9463ec 432 file->nrefs++;
221cc3ce 433
5e9463ec
MT
434 return file;
435}
221cc3ce 436
5803b5f6 437PAKFIRE_EXPORT struct pakfire_file* pakfire_file_unref(struct pakfire_file* file) {
5e9463ec
MT
438 if (--file->nrefs > 0)
439 return file;
440
441 pakfire_file_free(file);
442 return NULL;
221cc3ce
MT
443}
444
2f3563b9
MT
445/*
446 Flags
447*/
448
449int pakfire_file_has_flag(struct pakfire_file* file, int flag) {
450 return file->flags & flag;
451}
452
453int pakfire_file_set_flags(struct pakfire_file* file, int flag) {
454 file->flags |= flag;
455
456 return 0;
457}
458
5852b822
MT
459#define pakfire_file_strmode(file, buffer) \
460 __pakfire_file_strmode(file, buffer, sizeof(buffer))
461
462static int __pakfire_file_strmode(struct pakfire_file* file, char* s, const size_t length) {
463 int r;
464
465 static const mode_t permbits[] = {
466 0400,
467 0200,
468 0100,
469 0040,
470 0020,
471 0010,
472 0004,
473 0002,
474 0001
475 };
476
477 const mode_t mode = pakfire_file_get_mode(file);
478 const mode_t type = pakfire_file_get_type(file);
479
480 // Set some default string
481 r = __pakfire_string_set(s, length, "?rwxrwxrwx ");
482 if (r)
483 return r;
484
485 switch (type) {
486 case S_IFREG:
487 s[0] = '-';
488 break;
489
490 case S_IFBLK:
491 s[0] = 'b';
492 break;
493
494 case S_IFCHR:
495 s[0] = 'c';
496 break;
497
498 case S_IFDIR:
499 s[0] = 'd';
500 break;
501
502 case S_IFLNK:
503 s[0] = 'l';
504 break;
505
506 case S_IFSOCK:
507 s[0] = 's';
508 break;
509
510 case S_IFIFO:
511 s[0] = 'p';
512 break;
513
514 default:
515 if (*file->hardlink) {
516 s[0] = 'h';
517 break;
518 }
519 }
520
521 for (unsigned int i = 0; i < 9; i++) {
522 if (mode & permbits[i])
523 continue;
524
525 s[i+1] = '-';
526 }
527
528 if (mode & S_ISUID) {
529 if (mode & 0100)
530 s[3] = 's';
531 else
532 s[3] = 'S';
533 }
534
535 if (mode & S_ISGID) {
536 if (mode & 0010)
537 s[6] = 's';
538 else
539 s[6] = 'S';
540 }
541
542 if (mode & S_ISVTX) {
543 if (mode & 0001)
544 s[9] = 't';
545 else
546 s[9] = 'T';
547 }
548
549#if 0
550 if (file->caps)
551 s[10] = '+';
552#endif
553
554 return 0;
555}
556
f7f44921
MT
557char* pakfire_file_dump(struct pakfire_file* file, int flags) {
558 char* buffer = "";
5852b822
MT
559 int r;
560
561 char mode[12];
562 char time[32];
563
564 // Format mode
f7f44921
MT
565 if (flags & PAKFIRE_FILE_DUMP_MODE) {
566 r = pakfire_file_strmode(file, mode);
567 if (r)
568 goto ERROR;
569
570 r = asprintf(&buffer, "%s %s", buffer, mode);
571 if (r < 0)
572 goto ERROR;
573 }
574
575 // Format ownership
576 if (flags & PAKFIRE_FILE_DUMP_OWNERSHIP) {
577 r = asprintf(&buffer, "%s %s/%s", buffer, file->uname, file->gname);
578 if (r < 0)
579 goto ERROR;
580 }
581
582 // Format size
583 if (flags & PAKFIRE_FILE_DUMP_SIZE) {
584 r = asprintf(&buffer, "%s %8zu", buffer, file->st.st_size);
585 if (r < 0)
586 goto ERROR;
587 }
5852b822
MT
588
589 // Format time
f7f44921
MT
590 if (flags & PAKFIRE_FILE_DUMP_TIME) {
591 r = pakfire_strftime(time, "%Y-%m-%d %H:%M", file->st.st_ctime);
592 if (r)
593 goto ERROR;
594
595 r = asprintf(&buffer, "%s %s", buffer, time);
596 if (r < 0)
597 goto ERROR;
598 }
5852b822 599
f7f44921
MT
600 // Format path
601 r = asprintf(&buffer, "%s %s", buffer, file->path);
5852b822 602 if (r < 0)
f7f44921 603 goto ERROR;
5852b822 604
a3bf05ad 605 // Append symlink target
f7f44921
MT
606 if (flags & PAKFIRE_FILE_DUMP_LINK_TARGETS) {
607 switch (pakfire_file_get_type(file)) {
608 case S_IFLNK:
609 r = asprintf(&buffer, "%s -> %s", buffer, file->symlink);
610 if (r < 0)
611 return NULL;
a3bf05ad 612
f7f44921
MT
613 default:
614 break;
615 }
616 }
617
28886e21
MT
618 // Dump Issues
619 if (flags & PAKFIRE_FILE_DUMP_ISSUES) {
620 if (file->issues & PAKFIRE_FILE_FHS_ERROR) {
6d9dd7bc
MT
621 r = asprintf(&buffer, "%s [FHS-ERROR]", buffer);
622 if (r < 0)
623 goto ERROR;
624 }
625
03a5ac95
MT
626 if (file->issues & PAKFIRE_FILE_MISSING_DEBUGINFO) {
627 r = asprintf(&buffer, "%s [MISSING-DEBUGINFO]", buffer);
628 if (r < 0)
629 goto ERROR;
630 }
631
62bf2777 632 // Stack-smashing Protection
d8acc837
MT
633 if (file->issues & PAKFIRE_FILE_MISSING_SSP) {
634 r = asprintf(&buffer, "%s [MISSING-SSP]", buffer);
62bf2777
MT
635 if (r < 0)
636 goto ERROR;
637 }
f7f44921 638
62bf2777 639 // Position-independent Executable
d8acc837
MT
640 if (file->issues & PAKFIRE_FILE_MISSING_PIE) {
641 r = asprintf(&buffer, "%s [MISSING-PIE]", buffer);
62bf2777
MT
642 if (r < 0)
643 goto ERROR;
644 }
03d5abd3 645
62bf2777
MT
646 // Executable Stack
647 if (file->issues & PAKFIRE_FILE_EXECSTACK) {
648 r = asprintf(&buffer, "%s [EXECSTACK]", buffer);
649 if (r < 0)
650 goto ERROR;
651 }
03d5abd3 652
62bf2777
MT
653 // Not Partially RELRO
654 if (file->issues & PAKFIRE_FILE_NO_PARTIALLY_RELRO) {
655 r = asprintf(&buffer, "%s [NO-PART-RELRO]", buffer);
656 if (r < 0)
657 goto ERROR;
f7f44921 658 }
a3bf05ad
MT
659 }
660
5852b822 661 return buffer;
f7f44921
MT
662
663ERROR:
664 if (buffer)
665 free(buffer);
666
667 return NULL;
5852b822
MT
668}
669
5803b5f6 670PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_file* file2) {
32485f6c
MT
671 const char* path1 = pakfire_file_get_path(file1);
672 const char* path2 = pakfire_file_get_path(file2);
221cc3ce 673
32485f6c 674 return strcmp(path1, path2);
221cc3ce
MT
675}
676
5803b5f6 677const char* pakfire_file_get_abspath(struct pakfire_file* file) {
e4c2f7a9
MT
678 return file->abspath;
679}
680
5803b5f6 681int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) {
49a39ad9
MT
682 int r;
683
d13bd5b7
MT
684 // Check if path is set and absolute
685 if (!path || *path != '/') {
686 errno = EINVAL;
687 return 1;
688 }
689
49a39ad9
MT
690 // Store the abspath
691 r = pakfire_string_set(file->abspath, path);
692 if (r)
693 goto ERROR;
694
695 // Store path if it isn't set, yet
696 if (!*file->path) {
697 r = pakfire_file_set_path(file, path);
698 if (r)
699 goto ERROR;
700 }
701
702 return r;
703
704ERROR:
705 ERROR(file->pakfire, "Could not set abspath '%s': %m\n", path);
706 return r;
3b9e3970
MT
707}
708
5803b5f6 709PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) {
32485f6c 710 return file->path;
221cc3ce
MT
711}
712
5803b5f6 713PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) {
12a327de 714 int r = 1;
520213e9 715
2cc8b5f4
MT
716 // Check if path is set
717 if (!path) {
d13bd5b7 718 errno = EINVAL;
12a327de 719 goto ERROR;
d13bd5b7
MT
720 }
721
2cc8b5f4
MT
722 // Strip any leading dots from paths
723 if (pakfire_string_startswith(path, "./"))
724 path++;
725
726 switch (*path) {
727 // Just store the path if it is absolute
728 case '/':
729 r = pakfire_string_set(file->path, path);
730 if (r)
731 goto ERROR;
732 break;
733
734 // Handle relative paths
735 default:
736 r = pakfire_string_format(file->path, "/%s", path);
737 if (r)
738 goto ERROR;
739 break;
740 }
520213e9
MT
741
742 // Set abspath if it isn't set, yet
743 if (!*file->abspath) {
2cc8b5f4 744 r = pakfire_file_set_abspath(file, file->path);
520213e9 745 if (r)
12a327de 746 goto ERROR;
520213e9
MT
747 }
748
749 return r;
12a327de
MT
750
751ERROR:
752 ERROR(file->pakfire, "Could not set path '%s': %m\n", path);
753 return r;
221cc3ce
MT
754}
755
59d8c727
MT
756PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) {
757 if (!*file->hardlink)
758 return NULL;
759
760 return file->hardlink;
761}
762
763PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) {
3c8eb581 764 pakfire_string_set(file->hardlink, link);
59d8c727
MT
765}
766
767PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) {
768 if (!*file->symlink)
769 return NULL;
770
771 return file->symlink;
772}
773
774PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) {
3c8eb581 775 pakfire_string_set(file->symlink, link);
59d8c727
MT
776}
777
f8733b31
MT
778PAKFIRE_EXPORT nlink_t pakfire_file_get_nlink(struct pakfire_file* file) {
779 return file->st.st_nlink;
780}
781
782PAKFIRE_EXPORT void pakfire_file_set_nlink(struct pakfire_file* file, const nlink_t nlink) {
783 file->st.st_nlink = nlink;
784}
785
786PAKFIRE_EXPORT ino_t pakfire_file_get_inode(struct pakfire_file* file) {
787 return file->st.st_ino;
788}
789
790PAKFIRE_EXPORT void pakfire_file_set_inode(struct pakfire_file* file, const ino_t ino) {
791 file->st.st_ino = ino;
792}
793
794PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) {
795 return file->st.st_dev;
796}
797
798PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, const dev_t dev) {
799 file->st.st_dev = dev;
800}
801
5803b5f6 802PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) {
a09b95e0 803 return file->st.st_mode & S_IFMT;
221cc3ce
MT
804}
805
a09b95e0
MT
806PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) {
807 return file->st.st_size;
221cc3ce
MT
808}
809
a09b95e0
MT
810PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) {
811 file->st.st_size = size;
221cc3ce
MT
812}
813
302e3253
MT
814PAKFIRE_EXPORT const char* pakfire_file_get_uname(struct pakfire_file* file) {
815 return file->uname;
221cc3ce
MT
816}
817
302e3253
MT
818PAKFIRE_EXPORT int pakfire_file_set_uname(struct pakfire_file* file, const char* uname) {
819 return pakfire_string_set(file->uname, uname);
221cc3ce
MT
820}
821
302e3253
MT
822PAKFIRE_EXPORT const char* pakfire_file_get_gname(struct pakfire_file* file) {
823 return file->gname;
221cc3ce
MT
824}
825
302e3253
MT
826PAKFIRE_EXPORT int pakfire_file_set_gname(struct pakfire_file* file, const char* gname) {
827 return pakfire_string_set(file->gname, gname);
221cc3ce
MT
828}
829
5803b5f6 830PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) {
a09b95e0 831 return file->st.st_mode;
221cc3ce
MT
832}
833
5803b5f6 834PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) {
a09b95e0 835 file->st.st_mode = mode;
221cc3ce
MT
836}
837
134545d5 838PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) {
966368aa 839 return file->st.st_mode & ~S_IFMT;
134545d5
MT
840}
841
842PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) {
843 // Clear any previous permissions
a09b95e0 844 file->st.st_mode &= S_IFMT;
134545d5
MT
845
846 // Set new bits (with format cleared)
a09b95e0 847 file->st.st_mode |= ~S_IFMT & perms;
134545d5
MT
848}
849
5803b5f6 850PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) {
a09b95e0 851 return file->st.st_ctime;
ef4e8460
MT
852}
853
5803b5f6 854PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) {
a09b95e0 855 file->st.st_ctime = time;
ef4e8460
MT
856}
857
5803b5f6 858PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) {
a09b95e0 859 return file->st.st_mtime;
221cc3ce
MT
860}
861
5803b5f6 862PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) {
a09b95e0 863 file->st.st_mtime = time;
221cc3ce
MT
864}
865
65131b30 866PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest(
c52e0148 867 struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) {
65131b30 868
9802aaf6 869 switch (type) {
d98740de
MT
870 case PAKFIRE_DIGEST_SHA3_512:
871 if (!pakfire_digest_set(file->digests.sha3_512))
872 return NULL;
873
874 if (length)
875 *length = sizeof(file->digests.sha3_512);
876
877 return file->digests.sha3_512;
878
879 case PAKFIRE_DIGEST_SHA3_256:
880 if (!pakfire_digest_set(file->digests.sha3_256))
881 return NULL;
882
883 if (length)
884 *length = sizeof(file->digests.sha3_256);
885
886 return file->digests.sha3_256;
887
f1e6c5df
MT
888 case PAKFIRE_DIGEST_BLAKE2B512:
889 if (!pakfire_digest_set(file->digests.blake2b512))
890 return NULL;
891
892 if (length)
893 *length = sizeof(file->digests.blake2b512);
894
895 return file->digests.blake2b512;
896
897 case PAKFIRE_DIGEST_BLAKE2S256:
898 if (!pakfire_digest_set(file->digests.blake2s256))
899 return NULL;
900
901 if (length)
902 *length = sizeof(file->digests.blake2s256);
903
904 return file->digests.blake2s256;
905
4500ed0a
MT
906 case PAKFIRE_DIGEST_SHA2_512:
907 if (!pakfire_digest_set(file->digests.sha2_512))
9802aaf6 908 return NULL;
65131b30 909
9802aaf6 910 if (length)
4500ed0a 911 *length = sizeof(file->digests.sha2_512);
65131b30 912
4500ed0a 913 return file->digests.sha2_512;
9802aaf6 914
4500ed0a
MT
915 case PAKFIRE_DIGEST_SHA2_256:
916 if (!pakfire_digest_set(file->digests.sha2_256))
9802aaf6 917 return NULL;
5e8dfbeb 918
9802aaf6 919 if (length)
4500ed0a 920 *length = sizeof(file->digests.sha2_256);
5e8dfbeb 921
4500ed0a 922 return file->digests.sha2_256;
2c4b4a02
MT
923
924 case PAKFIRE_DIGEST_UNDEFINED:
925 break;
5e8dfbeb
MT
926 }
927
9802aaf6 928 return NULL;
5e8dfbeb
MT
929}
930
931PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file,
c52e0148 932 const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
9802aaf6 933 if (!digest) {
5e8dfbeb
MT
934 errno = EINVAL;
935 return 1;
936 }
937
399d14c2
MT
938 // Check buffer length
939 if (pakfire_digest_length(type) != length) {
940 ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length);
941 errno = ENOMSG;
942 return 1;
943 }
944
945 // Store the digest
9802aaf6 946 switch (type) {
d98740de
MT
947 case PAKFIRE_DIGEST_SHA3_512:
948 memcpy(file->digests.sha3_512, digest, sizeof(file->digests.sha3_512));
949 break;
950
951 case PAKFIRE_DIGEST_SHA3_256:
952 memcpy(file->digests.sha3_256, digest, sizeof(file->digests.sha3_256));
953 break;
954
f1e6c5df
MT
955 case PAKFIRE_DIGEST_BLAKE2B512:
956 memcpy(file->digests.blake2b512, digest, sizeof(file->digests.blake2b512));
957 break;
958
959 case PAKFIRE_DIGEST_BLAKE2S256:
960 memcpy(file->digests.blake2s256, digest, sizeof(file->digests.blake2s256));
961 break;
962
4500ed0a
MT
963 case PAKFIRE_DIGEST_SHA2_512:
964 memcpy(file->digests.sha2_512, digest, sizeof(file->digests.sha2_512));
9802aaf6 965 break;
65131b30 966
4500ed0a
MT
967 case PAKFIRE_DIGEST_SHA2_256:
968 memcpy(file->digests.sha2_256, digest, sizeof(file->digests.sha2_256));
9802aaf6 969 break;
2c4b4a02
MT
970
971 case PAKFIRE_DIGEST_UNDEFINED:
972 errno = ENOTSUP;
973 return 1;
5e8dfbeb
MT
974 }
975
5e8dfbeb 976 return 0;
221cc3ce
MT
977}
978
5803b5f6 979static int pakfire_file_levels(struct pakfire_file* file) {
3fca5032
MT
980 if (!*file->path)
981 return 0;
982
983 int levels = 0;
984
985 for (char* p = file->path; *p; p++) {
986 if (*p == '/')
987 levels++;
988 }
989
990 return levels;
991}
992
d5a13ade
MT
993FILE* pakfire_file_open(struct pakfire_file* file) {
994 FILE* f = fopen(file->abspath, "r");
995 if (!f)
996 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
997
998 return f;
999}
1000
fabc09a9
MT
1001int pakfire_file_payload_matches(struct pakfire_file* file,
1002 const void* needle, const size_t length) {
1003 char buffer[1024 * 1024];
1004 FILE* f = NULL;
1005 void* p = NULL;
1006 int r;
1007
1008 // Only run for regular files
1009 if (!S_ISREG(file->st.st_mode))
1010 return 0;
1011
e4d7e9b4
MT
1012 // Skip empty files
1013 if (!file->st.st_size)
1014 return 0;
1015
fabc09a9
MT
1016 // Open the file
1017 f = pakfire_file_open(file);
ede8bda8
MT
1018 if (!f) {
1019 r = 1;
fabc09a9 1020 goto ERROR;
ede8bda8 1021 }
fabc09a9 1022
fabc09a9
MT
1023 while (!feof(f)) {
1024 size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
1025
1026 // Raise any reading errors
1027 if (ferror(f)) {
1028 r = 1;
1029 goto ERROR;
1030 }
1031
1032 // Search for the needle
1033 p = memmem(buffer, bytes_read, needle, length);
fabc09a9
MT
1034 if (p) {
1035 r = 1;
1036 goto ERROR;
1037 }
1038 }
1039
1040 // No match
1041 r = 0;
1042
1043ERROR:
1044 if (f)
1045 fclose(f);
1046
1047 return r;
1048}
1049
1e76689a
MT
1050static int __pakfire_file_compute_digests(struct pakfire_file* file,
1051 struct pakfire_digests* digests, const int types) {
1052 FILE* f = NULL;
1053 int r = 1;
1054
1055 // Skip this for anything that isn't a regular file
1056 if (!S_ISREG(file->st.st_mode))
1057 return 0;
1058
1059 // Reset digests
1060 pakfire_digests_reset(digests, types);
1061
1062 // Open the file
1063 f = pakfire_file_open(file);
1064 if (!f)
1065 goto ERROR;
1066
1067 // Compute digests
1068 r = pakfire_digests_compute_from_file(file->pakfire, digests, types, f);
1069 if (r)
1070 goto ERROR;
1071
1072ERROR:
1073 if (f)
1074 fclose(f);
1075
1076 return r;
1077}
1078
1079int pakfire_file_compute_digests(struct pakfire_file* file, const int types) {
6b32db11 1080 return __pakfire_file_compute_digests(file, &file->digests, types);
1e76689a
MT
1081}
1082
ac71886a 1083int pakfire_file_remove(struct pakfire_file* file) {
3fca5032
MT
1084 if (!*file->abspath) {
1085 errno = EINVAL;
1086 return 1;
1087 }
1088
1089 DEBUG(file->pakfire, "Removing %s...\n", file->path);
1090
1091 int r = remove(file->abspath);
1092 if (r) {
da89e02f
MT
1093 switch (errno) {
1094 // Ignore when we could not remove directories
1095 case ENOTEMPTY:
1096 return 0;
1097
1098 // Ignore if the file didn't exist
1099 case ENOENT:
1100 return 0;
1101
1102 default:
1103 break;
1104 }
3fca5032 1105
b1772bfb 1106 ERROR(file->pakfire, "Could not remove %s (%s): %m\n", file->path, file->abspath);
3fca5032
MT
1107 }
1108
ac71886a
MT
1109 return r;
1110}
1111
7434fa90
MT
1112int pakfire_file_symlink_target_exists(struct pakfire_file* file) {
1113 // Fail if this got called for anything that isn't a symlink
1114 if (!S_ISLNK(file->st.st_mode)) {
1115 errno = EINVAL;
1116 return -1;
1117 }
1118
1119 return pakfire_path_exists(file->abspath);
1120}
1121
210aabe9
MT
1122/*
1123 MIME Type
1124*/
1125
1126int pakfire_file_detect_mimetype(struct pakfire_file* file) {
1127 // Only process regular files
1128 if (!S_ISREG(file->st.st_mode))
1129 return 0;
1130
1131 // Skip if MIME type is already set
1132 if (*file->mimetype)
1133 return 0;
1134
1135 // Fetch the magic cookie
1136 magic_t magic = pakfire_get_magic(file->pakfire);
1137 if (!magic)
1138 return 1;
1139
1140 // Check the file
1141 const char* mimetype = magic_file(magic, file->abspath);
1142 if (!mimetype) {
1143 ERROR(file->pakfire, "Could not classify %s: %s\n", file->path, magic_error(magic));
1144 return 1;
1145 }
1146
1147 DEBUG(file->pakfire, "Classified %s as %s\n", file->path, mimetype);
1148
1149 // Store the value
1150 return pakfire_file_set_mimetype(file, mimetype);
1151}
1152
1153PAKFIRE_EXPORT const char* pakfire_file_get_mimetype(struct pakfire_file* file) {
1154 // Return nothing on an empty mimetype
1155 if (!*file->mimetype)
1156 return NULL;
1157
1158 return file->mimetype;
1159}
1160
1161PAKFIRE_EXPORT int pakfire_file_set_mimetype(
1162 struct pakfire_file* file, const char* mimetype) {
1163 // Store the value
1164 return pakfire_string_set(file->mimetype, mimetype);
1165}
1166
71f6f465
MT
1167/*
1168 Classification
1169*/
1170
df71dc60
MT
1171static int setup_libelf(struct pakfire* pakfire) {
1172 // Initialize libelf
1173 if (elf_version(EV_CURRENT) == EV_NONE) {
1174 ERROR(pakfire, "Could not initialize libelf: %s\n", elf_errmsg(-1));
1175
1176 return 1;
1177 }
1178
1179 return 0;
1180}
1181
71f6f465
MT
1182static int pakfire_file_classify_mode(struct pakfire_file* file) {
1183 // Check for regular files
72a36c9d 1184 if (S_ISREG(file->st.st_mode)) {
71f6f465
MT
1185 file->class |= PAKFIRE_FILE_REGULAR;
1186
72a36c9d
MT
1187 // Does the file have executable permissions?
1188 if (file->st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1189 file->class |= PAKFIRE_FILE_EXECUTABLE;
1190
71f6f465 1191 // Check for directories
72a36c9d 1192 } else if (S_ISDIR(file->st.st_mode))
71f6f465
MT
1193 file->class |= PAKFIRE_FILE_DIRECTORY;
1194
1195 // Check for symlinks
1196 else if (S_ISLNK(file->st.st_mode))
1197 file->class |= PAKFIRE_FILE_SYMLINK;
1198
1199 // Check for character devices
1200 else if (S_ISCHR(file->st.st_mode))
1201 file->class |= PAKFIRE_FILE_CHARACTER;
1202
1203 // Check for block devices
1204 else if (S_ISBLK(file->st.st_mode))
1205 file->class |= PAKFIRE_FILE_BLOCK;
1206
1207 // Check for FIFO pipes
1208 else if (S_ISFIFO(file->st.st_mode))
1209 file->class |= PAKFIRE_FILE_FIFO;
1210
1211 // Check for sockets
1212 else if (S_ISSOCK(file->st.st_mode))
1213 file->class |= PAKFIRE_FILE_SOCKET;
1214
1215 return 0;
1216}
1217
239230c2
MT
1218static const struct pattern {
1219 const char* pattern;
71f6f465 1220 int class;
239230c2 1221} patterns[] = {
d0831491
MT
1222 { "*.a", PAKFIRE_FILE_STATIC_LIBRARY },
1223 { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE },
71f6f465
MT
1224 { "*.pm", PAKFIRE_FILE_PERL },
1225 { "*.pc", PAKFIRE_FILE_PKGCONFIG },
ec95c0c4 1226 { "/usr/lib/firmware/*", PAKFIRE_FILE_FIRMWARE },
fc35e5cc 1227 { "/usr/lib*/ld-*.so*", PAKFIRE_FILE_RUNTIME_LINKER },
239230c2 1228 { NULL },
71f6f465
MT
1229};
1230
239230c2
MT
1231static int pakfire_file_classify_pattern(struct pakfire_file* file) {
1232 for (const struct pattern* p = patterns; p->pattern; p++) {
1233 if (pakfire_file_matches(file, p->pattern)) {
1234 file->class |= p->class;
71f6f465
MT
1235 break;
1236 }
1237 }
1238
1239 return 0;
1240}
1241
1242static const struct mimetype {
1243 const char* mimetype;
1244 int class;
1245} mimetypes[] = {
71f6f465
MT
1246 { "text/x-perl", PAKFIRE_FILE_PERL },
1247 { NULL, 0 },
1248};
1249
1250static int pakfire_file_classify_magic(struct pakfire_file* file) {
210aabe9
MT
1251 int r;
1252
210aabe9
MT
1253 // Detect the MIME type
1254 r = pakfire_file_detect_mimetype(file);
1255 if (r)
1256 return r;
71f6f465 1257
210aabe9
MT
1258 // Fetch the MIME type
1259 const char* mimetype = pakfire_file_get_mimetype(file);
1260 if (!mimetype)
71f6f465 1261 return 1;
71f6f465 1262
210aabe9 1263 // Match the MIME type with a flag
71f6f465
MT
1264 for (const struct mimetype* m = mimetypes; m->mimetype; m++) {
1265 if (strcmp(m->mimetype, mimetype) == 0) {
1266 file->class |= m->class;
1267 break;
1268 }
1269 }
1270
1271 return 0;
1272}
1273
df71dc60
MT
1274static int pakfire_file_classify_elf(struct pakfire_file* file) {
1275 FILE* f = NULL;
1276 Elf* elf = NULL;
1277 int r;
1278
1279 // Don't run this if we already know that file is an ELF file
1280 if (file->class & PAKFIRE_FILE_ELF)
1281 return 0;
1282
1283 // Setup libelf
1284 r = setup_libelf(file->pakfire);
1285 if (r)
1286 return r;
1287
1288 // Open the file
1289 f = fopen(file->abspath, "r");
1290 if (!f) {
1291 ERROR(file->pakfire, "Could not open %s: %m\n", file->path);
1292 return 1;
1293 }
1294
1295 // Try to open the ELF file
1296 elf = elf_begin(fileno(f), ELF_C_READ, NULL);
1297 if (!elf) {
1298 // We fail silently here, because this file might be in a different format
1299 goto ERROR;
1300 }
1301
1302 switch (elf_kind(elf)) {
1303 // Mark this file as an ELF file
1304 case ELF_K_ELF:
1305 file->class |= PAKFIRE_FILE_ELF;
1306 break;
1307
1308 // Ignore everything else
1309 default:
1310 break;
1311 }
1312
1313ERROR:
1314 if (elf)
1315 elf_end(elf);
1316 if (f)
1317 fclose(f);
1318
1319 return 0;
1320}
1321
71f6f465
MT
1322int pakfire_file_classify(struct pakfire_file* file) {
1323 int r;
1324
1325 if (!file->class) {
1326 // First, check the mode so that we won't run magic on directories, symlinks, ...
1327 r = pakfire_file_classify_mode(file);
1328 if (r)
1329 goto ERROR;
1330
1331 // Only run this for regular files
1332 if (file->class & PAKFIRE_FILE_REGULAR) {
239230c2
MT
1333 // Then check for patterns
1334 r = pakfire_file_classify_pattern(file);
71f6f465
MT
1335 if (r)
1336 goto ERROR;
1337
1338 // After that, we will use libmagic...
1339 r = pakfire_file_classify_magic(file);
1340 if (r)
df71dc60
MT
1341 goto ERROR;
1342
1343 // Check if the file is an ELF file
1344 r = pakfire_file_classify_elf(file);
1345 if (r)
71f6f465
MT
1346 goto ERROR;
1347 }
1348 }
1349
1350 return file->class;
1351
1352ERROR:
1353 // Reset the class
1354 file->class = PAKFIRE_FILE_UNKNOWN;
1355
1356 return r;
1357}
1358
1359int pakfire_file_matches_class(struct pakfire_file* file, const int class) {
1360 return pakfire_file_classify(file) & class;
1361}
1362
ac71886a
MT
1363/*
1364 This function tries to remove the file after it has been packaged.
1365
1366 It will try to delete any parent directories as well and ignore if directories
1367 cannot be deleted because they might contain other files
1368*/
1369int pakfire_file_cleanup(struct pakfire_file* file) {
1370 char path[PATH_MAX];
1371
1372 // Try removing the file
1373 int r = pakfire_file_remove(file);
1374 if (r)
1375 return r;
1376
3fca5032
MT
1377 // Create a working copy of abspath
1378 r = pakfire_string_set(path, file->abspath);
a60955af 1379 if (r)
3fca5032
MT
1380 return r;
1381
1382 // See how many levels this file has
1383 int levels = pakfire_file_levels(file);
1384
1385 // Walk all the way up and remove all parent directories if possible
1386 while (--levels) {
1387 dirname(path);
1388
1389 // Break if path is suddenly empty
1390 if (!*path)
1391 break;
1392
a8783709
MT
1393 DEBUG(file->pakfire, "Trying to remove parent directory %s\n", path);
1394
3fca5032 1395 r = rmdir(path);
3fca5032 1396
a8783709
MT
1397 // Break on any error
1398 if (r)
1399 break;
3fca5032
MT
1400 }
1401
a942166c 1402 return 0;
3fca5032 1403}
cf9bd6f4 1404
9e09e361 1405static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat* st) {
a09b95e0
MT
1406 const mode_t type = pakfire_file_get_type(file);
1407
9e09e361 1408 // Did the type change?
a09b95e0 1409 if (type != (st->st_mode & S_IFMT)) {
9e09e361
MT
1410 file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED;
1411
1412 DEBUG(file->pakfire, "%s: File Type changed\n", file->path);
1413 }
1414
a09b95e0
MT
1415 const mode_t perms = pakfire_file_get_perms(file);
1416
9e09e361 1417 // Check permissions
a09b95e0 1418 if (perms != (st->st_mode & 0777)) {
9e09e361
MT
1419 file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED;
1420
1421 DEBUG(file->pakfire, "%s: Permissions changed\n", file->path);
1422 }
1423
f8733b31
MT
1424#if 0
1425 // XXX This does not check what it is supposed to check
1426
9e09e361
MT
1427 // Check if device node changed
1428 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
a09b95e0
MT
1429 const dev_t dev = pakfire_file_get_dev(file);
1430
1431 if (dev != st->st_dev) {
9e09e361
MT
1432 file->verify_status |= PAKFIRE_FILE_DEV_CHANGED;
1433
1434 DEBUG(file->pakfire, "%s: Device Node changed\n", file->path);
1435 }
1436 }
f8733b31 1437#endif
9e09e361
MT
1438
1439 return 0;
1440}
1441
c0b051bb
MT
1442static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) {
1443 // Nothing to do if size matches
a09b95e0 1444 if (file->st.st_size == st->st_size)
c0b051bb
MT
1445 return 0;
1446
1447 // Size differs
d2b0e219 1448 file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED;
c0b051bb
MT
1449
1450 DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
a09b95e0 1451 file->path, file->st.st_size, st->st_size);
c0b051bb
MT
1452
1453 return 0;
1454}
1455
1456static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct stat* st) {
1457 // Fetch UID/GID
1458#if 0
1459 const uid_t uid = pakfire_unmap_id(file->pakfire, st->st_uid);
1460 const gid_t gid = pakfire_unmap_id(file->pakfire, st->st_gid);
1461#else
1462 const uid_t uid = st->st_uid;
1463 const gid_t gid = st->st_gid;
1464#endif
1465
1466 // Fetch owner & group
302e3253
MT
1467 struct passwd* owner = pakfire_getpwnam(file->pakfire, file->uname);
1468 struct group* group = pakfire_getgrnam(file->pakfire, file->gname);
c0b051bb
MT
1469
1470 // Check if owner matches
1471 if (!owner || owner->pw_uid != uid) {
d2b0e219 1472 file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED;
c0b051bb
MT
1473
1474 DEBUG(file->pakfire, "%s: Owner differs\n", file->path);
1475 }
1476
1477 // Check if group matches
1478 if (!group || group->gr_gid != gid) {
d2b0e219 1479 file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED;
c0b051bb
MT
1480
1481 DEBUG(file->pakfire, "%s: Group differs\n", file->path);
1482 }
1483
1484 return 0;
1485}
1486
0eeac4a5
MT
1487static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) {
1488 // Check creation time
a09b95e0 1489 if (file->st.st_ctime != st->st_ctime) {
0eeac4a5
MT
1490 file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED;
1491
1492 DEBUG(file->pakfire, "%s: Creation time changed\n", file->path);
1493 }
1494
1495 // Check modification time
a09b95e0 1496 if (file->st.st_mtime != st->st_mtime) {
0eeac4a5
MT
1497 file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED;
1498
1499 DEBUG(file->pakfire, "%s: Modification time changed\n", file->path);
1500 }
1501
1502 return 0;
1503}
1504
76011205 1505static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) {
76011205
MT
1506 int r;
1507
c52e0148 1508 struct pakfire_digests computed_digests;
293881bc 1509 int digest_types = PAKFIRE_DIGEST_UNDEFINED;
76011205
MT
1510
1511 // Nothing to do for anything that isn't a regular file
1512 if (!S_ISREG(st->st_mode))
1513 return 0;
1514
1515 // Fast-path if size changed. The payload will have changed, too
1516 if (file->verify_status & PAKFIRE_FILE_SIZE_CHANGED) {
1517 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
1518 return 0;
1519 }
1520
1521 // Check if this file has any digests at all
6b32db11 1522 digest_types = pakfire_digest_has_any(&file->digests);
76011205 1523
293881bc
MT
1524 if (!digest_types) {
1525 ERROR(file->pakfire, "%s: No digests available\n", file->path);
1526 return 0;
76011205
MT
1527 }
1528
293881bc 1529 // Compute digests
1e76689a 1530 r = __pakfire_file_compute_digests(file, &computed_digests, digest_types);
293881bc 1531 if (r)
76011205 1532 goto ERROR;
76011205 1533
293881bc
MT
1534 // Compare digests
1535 r = pakfire_digests_compare(file->pakfire, &file->digests, &computed_digests, digest_types);
76011205
MT
1536 if (r) {
1537 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
1538
293881bc 1539 DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path);
76011205
MT
1540 }
1541
76011205 1542ERROR:
76011205
MT
1543 return r;
1544}
1545
cf9bd6f4
MT
1546/*
1547 Verify the file - i.e. does the metadata match what is on disk?
1548*/
c0b051bb
MT
1549int pakfire_file_verify(struct pakfire_file* file, int* status) {
1550 struct stat st;
1551 int r;
1552
cf9bd6f4
MT
1553 DEBUG(file->pakfire, "Verifying %s...\n", file->path);
1554
c0b051bb
MT
1555 // stat() the file
1556 r = lstat(file->abspath, &st);
1557 if (r) {
1558 // File does not exist
1559 if (errno == ENOENT) {
1560 file->verify_status |= PAKFIRE_FILE_NOENT;
1561 return 1;
1562 }
1563
1564 // Raise any other errors from stat()
1565 return r;
1566 }
1567
9e09e361
MT
1568 // Verify mode
1569 r = pakfire_file_verify_mode(file, &st);
1570 if (r)
1571 return r;
1572
c0b051bb
MT
1573 // Verify size
1574 r = pakfire_file_verify_size(file, &st);
1575 if (r)
1576 return r;
1577
1578 // Verify ownership
1579 r = pakfire_file_verify_ownership(file, &st);
1580 if (r)
1581 return r;
1582
0eeac4a5
MT
1583 // Verify timestamps
1584 r = pakfire_file_verify_timestamps(file, &st);
1585 if (r)
1586 return r;
1587
76011205
MT
1588 // Verify payload
1589 r = pakfire_file_verify_payload(file, &st);
1590 if (r)
1591 return r;
1592
cf9bd6f4
MT
1593 return 0;
1594}
c064d9ec
MT
1595
1596PAKFIRE_EXPORT int pakfire_file_matches(struct pakfire_file* file, const char* pattern) {
1597 int r;
1598
1599 // Don't match on no pattern
1600 if (!pattern)
1601 return 0;
1602
1603 // Check if the pattern matches
1604 r = fnmatch(pattern, file->path, 0);
1605 switch (r) {
1606 // Match
1607 case 0:
1608 return 1;
1609
1610 // No Match
1611 case FNM_NOMATCH:
1612 return 0;
1613
1614 default:
1615 return -1;
1616 }
1617}
2dcb43e7
MT
1618
1619/*
1620 ELF Stuff
1621*/
1622
1623static int pakfire_file_open_elf(struct pakfire_file* file,
1624 int (*callback)(struct pakfire_file* file, Elf* elf, void* data), void* data) {
1625 FILE* f = NULL;
1626 Elf* elf = NULL;
1627 int r;
1628
1629 // Don't run this for non-ELF files
1630 if (!pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
1631 errno = EINVAL;
1632 return 1;
1633 }
1634
1635 // Setup libelf
1636 r = setup_libelf(file->pakfire);
1637 if (r)
1638 return r;
1639
1640 // Open the file
1641 f = fopen(file->abspath, "r");
1642 if (!f) {
1643 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
1644 return 1;
1645 }
1646
1647 // Parse the ELF header
1648 elf = elf_begin(fileno(f), ELF_C_READ, NULL);
1649 if (!elf) {
1650 ERROR(file->pakfire, "Could not open ELF file: %s\n", elf_errmsg(-1));
1651 r = 1;
1652 goto ERROR;
1653 }
1654
1655 // Check if this is an ELF file
1656 switch (elf_kind(elf)) {
1657 case ELF_K_ELF:
1658 break;
1659
1660 default:
1661 ERROR(file->pakfire, "%s is not an ELF object\n", file->path);
1662 r = 1;
1663 goto ERROR;
1664 }
1665
1666 // Call the callback
1667 r = callback(file, elf, data);
1668
1669ERROR:
1670 if (elf)
1671 elf_end(elf);
1672 if (f)
1673 fclose(f);
1674
1675 return r;
1676}
1677
0ef20579
MT
1678static Elf_Scn* pakfire_file_get_elf_section(struct pakfire_file* file,
1679 Elf* elf, const Elf64_Word type) {
1680 Elf_Scn* section = NULL;
1681 GElf_Shdr shdr;
1682
1683 // Walk through all sections
1684 for (;;) {
1685 section = elf_nextscn(elf, section);
1686 if (!section)
1687 break;
1688
1689 // Fetch the section header
1690 gelf_getshdr(section, &shdr);
1691
1692 // Return any matching sections
1693 if (shdr.sh_type == type)
1694 return section;
1695 }
1696
1697 // No section found
1698 return NULL;
1699}
1700
8a385eff
MT
1701static int __pakfire_file_get_elf_type(struct pakfire_file* file, Elf* elf, void* data) {
1702 int* type = (int*)data;
1703 GElf_Ehdr ehdr;
1704
1705 // Fetch the ELF header
1706 if (!gelf_getehdr(elf, &ehdr)) {
1707 ERROR(file->pakfire, "Could not parse ELF header: %s\n", elf_errmsg(-1));
1708 return 1;
1709 }
1710
1711 // Store the type
1712 *type = ehdr.e_type;
1713
1714 return 0;
1715}
1716
1717static int pakfire_file_get_elf_type(struct pakfire_file* file) {
1718 int type = ET_NONE;
1719 int r;
1720
1721 r = pakfire_file_open_elf(file, __pakfire_file_get_elf_type, &type);
1722 if (r)
1723 return -1;
1724
1725 return type;
1726}
1727
03a5ac95 1728static int __pakfire_file_check_debuginfo(struct pakfire_file* file, Elf* elf, void* data) {
0ef20579
MT
1729 // Fetch the symbol table
1730 Elf_Scn* symtab = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB);
8e8de3c1
MT
1731
1732 // Not found
0ef20579
MT
1733 if (!symtab) {
1734 DEBUG(file->pakfire, "%s has no debug sections\n", file->path);
8e8de3c1 1735
0ef20579
MT
1736 // Store the result
1737 file->issues |= PAKFIRE_FILE_MISSING_DEBUGINFO;
1738 }
8e8de3c1 1739
03a5ac95
MT
1740 return 0;
1741}
ec95c0c4 1742
03a5ac95 1743static int pakfire_file_check_debuginfo(struct pakfire_file* file) {
8a385eff
MT
1744 switch (pakfire_file_get_elf_type(file)) {
1745 // Do not check Relocatable Objects
1746 case ET_REL:
1747 return 0;
1748
1749 // Check everything else
1750 default:
1751 break;
1752 }
1753
03a5ac95 1754 return pakfire_file_open_elf(file, __pakfire_file_check_debuginfo, NULL);
8e8de3c1
MT
1755}
1756
28886e21 1757static int __pakfire_file_check_ssp(
2dcb43e7 1758 struct pakfire_file* file, Elf* elf, void* data) {
0ef20579
MT
1759 Elf_Scn* symtab = NULL;
1760 GElf_Shdr shdr;
2dcb43e7
MT
1761 Elf_Data* elf_data = NULL;
1762 GElf_Sym symbol;
1763 const char* name = NULL;
1764
0ef20579
MT
1765 // Fetch the symbol table
1766 symtab = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB);
1767 if (!symtab) {
1768 ERROR(file->pakfire, "%s has no symbol table\n", file->path);
1769 return 1;
1770 }
2dcb43e7 1771
0ef20579
MT
1772 // Fetch the section header
1773 gelf_getshdr(symtab, &shdr);
2dcb43e7 1774
0ef20579
MT
1775 // Count any global functions
1776 size_t counter = 0;
2dcb43e7
MT
1777
1778 // Fetch a pointer to the section data
0ef20579 1779 elf_data = elf_getdata(symtab, NULL);
2dcb43e7
MT
1780
1781 // Walk through all symbols
0ef20579 1782 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
2dcb43e7
MT
1783 gelf_getsym(elf_data, i, &symbol);
1784
1785 // Fetch the symbol name
0ef20579 1786 name = elf_strptr(elf, shdr.sh_link, symbol.st_name);
2dcb43e7
MT
1787
1788 // Skip empty section names
1789 if (!name || !*name)
1790 continue;
1791
f7f44921 1792 // Exit if there is a symbol called "__stack_chk_fail"
2dcb43e7 1793 if (pakfire_string_startswith(name, "__stack_chk_fail"))
f7f44921 1794 return 0;
0f7c90ef
MT
1795
1796 // Count any global functions
1797 if ((ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL) &&
1798 (ELF64_ST_TYPE(symbol.st_info) == STT_FUNC))
1799 counter++;
1800 }
1801
1802 // We do not perform the check for libraries that do not contain any functions.
1803 // Some packages use shared libraries to provide data.
1804 if (!counter) {
1805 DEBUG(file->pakfire, "%s: File has no functions. Skipping SSP check.\n", file->path);
1806 return 0;
2dcb43e7
MT
1807 }
1808
f7f44921 1809 // The file does not seem to have SSP enabled
d8acc837 1810 file->issues |= PAKFIRE_FILE_MISSING_SSP;
f7f44921 1811
2dcb43e7
MT
1812 return 0;
1813}
1814
28886e21 1815static int pakfire_file_check_ssp(struct pakfire_file* file) {
fc35e5cc
MT
1816 // Do not perform this check for runtime linkers
1817 if (pakfire_file_matches_class(file, PAKFIRE_FILE_RUNTIME_LINKER))
1818 return 0;
1819
03a5ac95
MT
1820 // We cannot perform this check if we don't have debuginfo
1821 if (file->issues & PAKFIRE_FILE_MISSING_DEBUGINFO)
1822 return 0;
1823
28886e21 1824 return pakfire_file_open_elf(file, __pakfire_file_check_ssp, NULL);
2dcb43e7 1825}
2a67d72c 1826
28886e21 1827static int pakfire_file_check_pie(struct pakfire_file* file) {
8a385eff
MT
1828 switch (pakfire_file_get_elf_type(file)) {
1829 // Shared Object files are good
2a67d72c 1830 case ET_DYN:
22e696bd 1831 break;
2a67d72c 1832
8a385eff 1833 // Everything else is bad
2a67d72c 1834 default:
d8acc837 1835 file->issues |= PAKFIRE_FILE_MISSING_PIE;
22e696bd 1836 break;
2a67d72c 1837 }
22e696bd
MT
1838
1839 return 0;
f7f44921
MT
1840}
1841
28886e21 1842static int __pakfire_file_check_execstack(
dae43e1f
MT
1843 struct pakfire_file* file, Elf* elf, void* data) {
1844 GElf_Phdr phdr;
1845 int r;
1846
1847 size_t phnum = 0;
1848
1849 // Fetch the total numbers of program headers
1850 r = elf_getphdrnum(elf, &phnum);
1851 if (r) {
1852 ERROR(file->pakfire, "Could not fetch number of program headers: %s\n",
1853 elf_errmsg(-1));
1854 return 1;
1855 }
1856
1857 // Walk through all program headers
1858 for (unsigned int i = 0; i < phnum; i++) {
1859 if (!gelf_getphdr(elf, i, &phdr)) {
1860 ERROR(file->pakfire, "Could not parse program header: %s\n", elf_errmsg(-1));
1861 return 1;
1862 }
1863
1864 switch (phdr.p_type) {
1865 case PT_GNU_STACK:
1866 DEBUG(file->pakfire,
1867 "%s: GNU_STACK flags: %c%c%c\n",
1868 file->path,
1869 (phdr.p_flags & PF_R) ? 'R' : '-',
1870 (phdr.p_flags & PF_W) ? 'W' : '-',
1871 (phdr.p_flags & PF_X) ? 'X' : '-'
1872 );
1873
1874 // The stack cannot be writable and executable
1875 if ((phdr.p_flags & PF_W) && (phdr.p_flags & PF_X))
28886e21 1876 file->issues |= PAKFIRE_FILE_EXECSTACK;
dae43e1f
MT
1877
1878 // Done
1879 return 0;
1880
1881 default:
1882 break;
1883 }
1884 }
1885
1886 return 0;
1887}
1888
28886e21
MT
1889static int pakfire_file_check_execstack(struct pakfire_file* file) {
1890 return pakfire_file_open_elf(file, __pakfire_file_check_execstack, NULL);
dae43e1f
MT
1891}
1892
28886e21 1893static int __pakfire_file_check_partially_relro(
d265bed6
MT
1894 struct pakfire_file* file, Elf* elf, void* data) {
1895 GElf_Phdr phdr;
1896 int r;
1897
1898 size_t phnum = 0;
1899
1900 // Fetch the total numbers of program headers
1901 r = elf_getphdrnum(elf, &phnum);
1902 if (r) {
1903 ERROR(file->pakfire, "Could not fetch number of program headers: %s\n",
1904 elf_errmsg(-1));
1905 return 1;
1906 }
1907
1908 // Walk through all program headers
1909 for (unsigned int i = 0; i < phnum; i++) {
1910 if (!gelf_getphdr(elf, i, &phdr)) {
1911 ERROR(file->pakfire, "Could not parse program header: %s\n", elf_errmsg(-1));
1912 return 1;
1913 }
1914
1915 switch (phdr.p_type) {
1916 case PT_GNU_RELRO:
1917 return 0;
1918
1919 default:
1920 break;
1921 }
1922 }
1923
1924 // This file does not seem to have PT_GNU_RELRO set
28886e21 1925 file->issues |= PAKFIRE_FILE_NO_PARTIALLY_RELRO;
d265bed6
MT
1926
1927 return 0;
1928}
1929
28886e21
MT
1930static int pakfire_file_check_relro(struct pakfire_file* file) {
1931 return pakfire_file_open_elf(file, __pakfire_file_check_partially_relro, NULL);
d265bed6
MT
1932}
1933
1934
28886e21 1935int pakfire_file_check(struct pakfire_file* file, int* issues) {
f7f44921
MT
1936 int r;
1937
1938 // Return previous result if this has been run before
28886e21 1939 if (!file->check_done) {
6d9dd7bc
MT
1940 // Perform FHS check
1941 r = pakfire_fhs_check_file(file->pakfire, file);
1942 if (r)
28886e21 1943 file->issues |= PAKFIRE_FILE_FHS_ERROR;
8a385eff 1944
6d9dd7bc
MT
1945 // Do not perform the following checks on firmware
1946 if (pakfire_file_matches_class(file, PAKFIRE_FILE_FIRMWARE))
1947 goto DONE;
8a385eff 1948
6d9dd7bc
MT
1949 // Run these checks only for ELF files
1950 if (pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
1951 switch (pakfire_file_get_elf_type(file)) {
1952 // Do not check Relocatable Objects
1953 case ET_REL:
1954 goto DONE;
1955
1956 // Check everything else
1957 default:
1958 break;
1959 }
f7f44921 1960
03a5ac95
MT
1961 // Check if the file has debug info
1962 r = pakfire_file_check_debuginfo(file);
1963 if (r)
1964 return r;
1965
6d9dd7bc 1966 // Check for SSP
28886e21 1967 r = pakfire_file_check_ssp(file);
6d9dd7bc
MT
1968 if (r)
1969 return r;
f7f44921 1970
6d9dd7bc 1971 // Check for PIE
28886e21 1972 r = pakfire_file_check_pie(file);
6d9dd7bc
MT
1973 if (r)
1974 return r;
dae43e1f 1975
6d9dd7bc 1976 // Check for executable stacks
28886e21 1977 r = pakfire_file_check_execstack(file);
6d9dd7bc
MT
1978 if (r)
1979 return r;
1980
1981 // Check for RELRO
28886e21 1982 r = pakfire_file_check_relro(file);
6d9dd7bc
MT
1983 if (r)
1984 return r;
1985 }
d265bed6 1986
8a385eff 1987DONE:
f7f44921 1988 // All checks done
28886e21 1989 file->check_done = 1;
f7f44921
MT
1990 }
1991
1992 // Return any issues
1993 if (issues)
28886e21 1994 *issues = file->issues;
f7f44921
MT
1995
1996 return 0;
2a67d72c 1997}