]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/file.c
file: Implement RPATH/RUNPATH check
[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 }
7b461c8b
MT
659
660 // Has RUNPATH?
661 if (file->issues & PAKFIRE_FILE_HAS_RUNPATH) {
662 r = asprintf(&buffer, "%s [HAS-RUNPATH]", buffer);
663 if (r < 0)
664 goto ERROR;
665 }
a3bf05ad
MT
666 }
667
5852b822 668 return buffer;
f7f44921
MT
669
670ERROR:
671 if (buffer)
672 free(buffer);
673
674 return NULL;
5852b822
MT
675}
676
5803b5f6 677PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_file* file2) {
32485f6c
MT
678 const char* path1 = pakfire_file_get_path(file1);
679 const char* path2 = pakfire_file_get_path(file2);
221cc3ce 680
32485f6c 681 return strcmp(path1, path2);
221cc3ce
MT
682}
683
5803b5f6 684const char* pakfire_file_get_abspath(struct pakfire_file* file) {
e4c2f7a9
MT
685 return file->abspath;
686}
687
5803b5f6 688int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) {
49a39ad9
MT
689 int r;
690
d13bd5b7
MT
691 // Check if path is set and absolute
692 if (!path || *path != '/') {
693 errno = EINVAL;
694 return 1;
695 }
696
49a39ad9
MT
697 // Store the abspath
698 r = pakfire_string_set(file->abspath, path);
699 if (r)
700 goto ERROR;
701
702 // Store path if it isn't set, yet
703 if (!*file->path) {
704 r = pakfire_file_set_path(file, path);
705 if (r)
706 goto ERROR;
707 }
708
709 return r;
710
711ERROR:
712 ERROR(file->pakfire, "Could not set abspath '%s': %m\n", path);
713 return r;
3b9e3970
MT
714}
715
5803b5f6 716PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) {
32485f6c 717 return file->path;
221cc3ce
MT
718}
719
5803b5f6 720PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) {
12a327de 721 int r = 1;
520213e9 722
2cc8b5f4
MT
723 // Check if path is set
724 if (!path) {
d13bd5b7 725 errno = EINVAL;
12a327de 726 goto ERROR;
d13bd5b7
MT
727 }
728
2cc8b5f4
MT
729 // Strip any leading dots from paths
730 if (pakfire_string_startswith(path, "./"))
731 path++;
732
733 switch (*path) {
734 // Just store the path if it is absolute
735 case '/':
736 r = pakfire_string_set(file->path, path);
737 if (r)
738 goto ERROR;
739 break;
740
741 // Handle relative paths
742 default:
743 r = pakfire_string_format(file->path, "/%s", path);
744 if (r)
745 goto ERROR;
746 break;
747 }
520213e9
MT
748
749 // Set abspath if it isn't set, yet
750 if (!*file->abspath) {
2cc8b5f4 751 r = pakfire_file_set_abspath(file, file->path);
520213e9 752 if (r)
12a327de 753 goto ERROR;
520213e9
MT
754 }
755
756 return r;
12a327de
MT
757
758ERROR:
759 ERROR(file->pakfire, "Could not set path '%s': %m\n", path);
760 return r;
221cc3ce
MT
761}
762
59d8c727
MT
763PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) {
764 if (!*file->hardlink)
765 return NULL;
766
767 return file->hardlink;
768}
769
770PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) {
3c8eb581 771 pakfire_string_set(file->hardlink, link);
59d8c727
MT
772}
773
774PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) {
775 if (!*file->symlink)
776 return NULL;
777
778 return file->symlink;
779}
780
781PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) {
3c8eb581 782 pakfire_string_set(file->symlink, link);
59d8c727
MT
783}
784
f8733b31
MT
785PAKFIRE_EXPORT nlink_t pakfire_file_get_nlink(struct pakfire_file* file) {
786 return file->st.st_nlink;
787}
788
789PAKFIRE_EXPORT void pakfire_file_set_nlink(struct pakfire_file* file, const nlink_t nlink) {
790 file->st.st_nlink = nlink;
791}
792
793PAKFIRE_EXPORT ino_t pakfire_file_get_inode(struct pakfire_file* file) {
794 return file->st.st_ino;
795}
796
797PAKFIRE_EXPORT void pakfire_file_set_inode(struct pakfire_file* file, const ino_t ino) {
798 file->st.st_ino = ino;
799}
800
801PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) {
802 return file->st.st_dev;
803}
804
805PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, const dev_t dev) {
806 file->st.st_dev = dev;
807}
808
5803b5f6 809PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) {
a09b95e0 810 return file->st.st_mode & S_IFMT;
221cc3ce
MT
811}
812
a09b95e0
MT
813PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) {
814 return file->st.st_size;
221cc3ce
MT
815}
816
a09b95e0
MT
817PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) {
818 file->st.st_size = size;
221cc3ce
MT
819}
820
302e3253
MT
821PAKFIRE_EXPORT const char* pakfire_file_get_uname(struct pakfire_file* file) {
822 return file->uname;
221cc3ce
MT
823}
824
302e3253
MT
825PAKFIRE_EXPORT int pakfire_file_set_uname(struct pakfire_file* file, const char* uname) {
826 return pakfire_string_set(file->uname, uname);
221cc3ce
MT
827}
828
302e3253
MT
829PAKFIRE_EXPORT const char* pakfire_file_get_gname(struct pakfire_file* file) {
830 return file->gname;
221cc3ce
MT
831}
832
302e3253
MT
833PAKFIRE_EXPORT int pakfire_file_set_gname(struct pakfire_file* file, const char* gname) {
834 return pakfire_string_set(file->gname, gname);
221cc3ce
MT
835}
836
5803b5f6 837PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) {
a09b95e0 838 return file->st.st_mode;
221cc3ce
MT
839}
840
5803b5f6 841PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) {
a09b95e0 842 file->st.st_mode = mode;
221cc3ce
MT
843}
844
134545d5 845PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) {
966368aa 846 return file->st.st_mode & ~S_IFMT;
134545d5
MT
847}
848
849PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) {
850 // Clear any previous permissions
a09b95e0 851 file->st.st_mode &= S_IFMT;
134545d5
MT
852
853 // Set new bits (with format cleared)
a09b95e0 854 file->st.st_mode |= ~S_IFMT & perms;
134545d5
MT
855}
856
5803b5f6 857PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) {
a09b95e0 858 return file->st.st_ctime;
ef4e8460
MT
859}
860
5803b5f6 861PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) {
a09b95e0 862 file->st.st_ctime = time;
ef4e8460
MT
863}
864
5803b5f6 865PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) {
a09b95e0 866 return file->st.st_mtime;
221cc3ce
MT
867}
868
5803b5f6 869PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) {
a09b95e0 870 file->st.st_mtime = time;
221cc3ce
MT
871}
872
65131b30 873PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest(
c52e0148 874 struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) {
65131b30 875
9802aaf6 876 switch (type) {
d98740de
MT
877 case PAKFIRE_DIGEST_SHA3_512:
878 if (!pakfire_digest_set(file->digests.sha3_512))
879 return NULL;
880
881 if (length)
882 *length = sizeof(file->digests.sha3_512);
883
884 return file->digests.sha3_512;
885
886 case PAKFIRE_DIGEST_SHA3_256:
887 if (!pakfire_digest_set(file->digests.sha3_256))
888 return NULL;
889
890 if (length)
891 *length = sizeof(file->digests.sha3_256);
892
893 return file->digests.sha3_256;
894
f1e6c5df
MT
895 case PAKFIRE_DIGEST_BLAKE2B512:
896 if (!pakfire_digest_set(file->digests.blake2b512))
897 return NULL;
898
899 if (length)
900 *length = sizeof(file->digests.blake2b512);
901
902 return file->digests.blake2b512;
903
904 case PAKFIRE_DIGEST_BLAKE2S256:
905 if (!pakfire_digest_set(file->digests.blake2s256))
906 return NULL;
907
908 if (length)
909 *length = sizeof(file->digests.blake2s256);
910
911 return file->digests.blake2s256;
912
4500ed0a
MT
913 case PAKFIRE_DIGEST_SHA2_512:
914 if (!pakfire_digest_set(file->digests.sha2_512))
9802aaf6 915 return NULL;
65131b30 916
9802aaf6 917 if (length)
4500ed0a 918 *length = sizeof(file->digests.sha2_512);
65131b30 919
4500ed0a 920 return file->digests.sha2_512;
9802aaf6 921
4500ed0a
MT
922 case PAKFIRE_DIGEST_SHA2_256:
923 if (!pakfire_digest_set(file->digests.sha2_256))
9802aaf6 924 return NULL;
5e8dfbeb 925
9802aaf6 926 if (length)
4500ed0a 927 *length = sizeof(file->digests.sha2_256);
5e8dfbeb 928
4500ed0a 929 return file->digests.sha2_256;
2c4b4a02
MT
930
931 case PAKFIRE_DIGEST_UNDEFINED:
932 break;
5e8dfbeb
MT
933 }
934
9802aaf6 935 return NULL;
5e8dfbeb
MT
936}
937
938PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file,
c52e0148 939 const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
9802aaf6 940 if (!digest) {
5e8dfbeb
MT
941 errno = EINVAL;
942 return 1;
943 }
944
399d14c2
MT
945 // Check buffer length
946 if (pakfire_digest_length(type) != length) {
947 ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length);
948 errno = ENOMSG;
949 return 1;
950 }
951
952 // Store the digest
9802aaf6 953 switch (type) {
d98740de
MT
954 case PAKFIRE_DIGEST_SHA3_512:
955 memcpy(file->digests.sha3_512, digest, sizeof(file->digests.sha3_512));
956 break;
957
958 case PAKFIRE_DIGEST_SHA3_256:
959 memcpy(file->digests.sha3_256, digest, sizeof(file->digests.sha3_256));
960 break;
961
f1e6c5df
MT
962 case PAKFIRE_DIGEST_BLAKE2B512:
963 memcpy(file->digests.blake2b512, digest, sizeof(file->digests.blake2b512));
964 break;
965
966 case PAKFIRE_DIGEST_BLAKE2S256:
967 memcpy(file->digests.blake2s256, digest, sizeof(file->digests.blake2s256));
968 break;
969
4500ed0a
MT
970 case PAKFIRE_DIGEST_SHA2_512:
971 memcpy(file->digests.sha2_512, digest, sizeof(file->digests.sha2_512));
9802aaf6 972 break;
65131b30 973
4500ed0a
MT
974 case PAKFIRE_DIGEST_SHA2_256:
975 memcpy(file->digests.sha2_256, digest, sizeof(file->digests.sha2_256));
9802aaf6 976 break;
2c4b4a02
MT
977
978 case PAKFIRE_DIGEST_UNDEFINED:
979 errno = ENOTSUP;
980 return 1;
5e8dfbeb
MT
981 }
982
5e8dfbeb 983 return 0;
221cc3ce
MT
984}
985
5803b5f6 986static int pakfire_file_levels(struct pakfire_file* file) {
3fca5032
MT
987 if (!*file->path)
988 return 0;
989
990 int levels = 0;
991
992 for (char* p = file->path; *p; p++) {
993 if (*p == '/')
994 levels++;
995 }
996
997 return levels;
998}
999
d5a13ade
MT
1000FILE* pakfire_file_open(struct pakfire_file* file) {
1001 FILE* f = fopen(file->abspath, "r");
1002 if (!f)
1003 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
1004
1005 return f;
1006}
1007
fabc09a9
MT
1008int pakfire_file_payload_matches(struct pakfire_file* file,
1009 const void* needle, const size_t length) {
1010 char buffer[1024 * 1024];
1011 FILE* f = NULL;
1012 void* p = NULL;
1013 int r;
1014
1015 // Only run for regular files
1016 if (!S_ISREG(file->st.st_mode))
1017 return 0;
1018
e4d7e9b4
MT
1019 // Skip empty files
1020 if (!file->st.st_size)
1021 return 0;
1022
fabc09a9
MT
1023 // Open the file
1024 f = pakfire_file_open(file);
ede8bda8
MT
1025 if (!f) {
1026 r = 1;
fabc09a9 1027 goto ERROR;
ede8bda8 1028 }
fabc09a9 1029
fabc09a9
MT
1030 while (!feof(f)) {
1031 size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
1032
1033 // Raise any reading errors
1034 if (ferror(f)) {
1035 r = 1;
1036 goto ERROR;
1037 }
1038
1039 // Search for the needle
1040 p = memmem(buffer, bytes_read, needle, length);
fabc09a9
MT
1041 if (p) {
1042 r = 1;
1043 goto ERROR;
1044 }
1045 }
1046
1047 // No match
1048 r = 0;
1049
1050ERROR:
1051 if (f)
1052 fclose(f);
1053
1054 return r;
1055}
1056
1e76689a
MT
1057static int __pakfire_file_compute_digests(struct pakfire_file* file,
1058 struct pakfire_digests* digests, const int types) {
1059 FILE* f = NULL;
1060 int r = 1;
1061
1062 // Skip this for anything that isn't a regular file
1063 if (!S_ISREG(file->st.st_mode))
1064 return 0;
1065
1066 // Reset digests
1067 pakfire_digests_reset(digests, types);
1068
1069 // Open the file
1070 f = pakfire_file_open(file);
1071 if (!f)
1072 goto ERROR;
1073
1074 // Compute digests
1075 r = pakfire_digests_compute_from_file(file->pakfire, digests, types, f);
1076 if (r)
1077 goto ERROR;
1078
1079ERROR:
1080 if (f)
1081 fclose(f);
1082
1083 return r;
1084}
1085
1086int pakfire_file_compute_digests(struct pakfire_file* file, const int types) {
6b32db11 1087 return __pakfire_file_compute_digests(file, &file->digests, types);
1e76689a
MT
1088}
1089
ac71886a 1090int pakfire_file_remove(struct pakfire_file* file) {
3fca5032
MT
1091 if (!*file->abspath) {
1092 errno = EINVAL;
1093 return 1;
1094 }
1095
1096 DEBUG(file->pakfire, "Removing %s...\n", file->path);
1097
1098 int r = remove(file->abspath);
1099 if (r) {
da89e02f
MT
1100 switch (errno) {
1101 // Ignore when we could not remove directories
1102 case ENOTEMPTY:
1103 return 0;
1104
1105 // Ignore if the file didn't exist
1106 case ENOENT:
1107 return 0;
1108
1109 default:
1110 break;
1111 }
3fca5032 1112
b1772bfb 1113 ERROR(file->pakfire, "Could not remove %s (%s): %m\n", file->path, file->abspath);
3fca5032
MT
1114 }
1115
ac71886a
MT
1116 return r;
1117}
1118
7434fa90
MT
1119int pakfire_file_symlink_target_exists(struct pakfire_file* file) {
1120 // Fail if this got called for anything that isn't a symlink
1121 if (!S_ISLNK(file->st.st_mode)) {
1122 errno = EINVAL;
1123 return -1;
1124 }
1125
1126 return pakfire_path_exists(file->abspath);
1127}
1128
210aabe9
MT
1129/*
1130 MIME Type
1131*/
1132
1133int pakfire_file_detect_mimetype(struct pakfire_file* file) {
1134 // Only process regular files
1135 if (!S_ISREG(file->st.st_mode))
1136 return 0;
1137
1138 // Skip if MIME type is already set
1139 if (*file->mimetype)
1140 return 0;
1141
1142 // Fetch the magic cookie
1143 magic_t magic = pakfire_get_magic(file->pakfire);
1144 if (!magic)
1145 return 1;
1146
1147 // Check the file
1148 const char* mimetype = magic_file(magic, file->abspath);
1149 if (!mimetype) {
1150 ERROR(file->pakfire, "Could not classify %s: %s\n", file->path, magic_error(magic));
1151 return 1;
1152 }
1153
1154 DEBUG(file->pakfire, "Classified %s as %s\n", file->path, mimetype);
1155
1156 // Store the value
1157 return pakfire_file_set_mimetype(file, mimetype);
1158}
1159
1160PAKFIRE_EXPORT const char* pakfire_file_get_mimetype(struct pakfire_file* file) {
1161 // Return nothing on an empty mimetype
1162 if (!*file->mimetype)
1163 return NULL;
1164
1165 return file->mimetype;
1166}
1167
1168PAKFIRE_EXPORT int pakfire_file_set_mimetype(
1169 struct pakfire_file* file, const char* mimetype) {
1170 // Store the value
1171 return pakfire_string_set(file->mimetype, mimetype);
1172}
1173
71f6f465
MT
1174/*
1175 Classification
1176*/
1177
df71dc60
MT
1178static int setup_libelf(struct pakfire* pakfire) {
1179 // Initialize libelf
1180 if (elf_version(EV_CURRENT) == EV_NONE) {
1181 ERROR(pakfire, "Could not initialize libelf: %s\n", elf_errmsg(-1));
1182
1183 return 1;
1184 }
1185
1186 return 0;
1187}
1188
71f6f465
MT
1189static int pakfire_file_classify_mode(struct pakfire_file* file) {
1190 // Check for regular files
72a36c9d 1191 if (S_ISREG(file->st.st_mode)) {
71f6f465
MT
1192 file->class |= PAKFIRE_FILE_REGULAR;
1193
72a36c9d
MT
1194 // Does the file have executable permissions?
1195 if (file->st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
1196 file->class |= PAKFIRE_FILE_EXECUTABLE;
1197
71f6f465 1198 // Check for directories
72a36c9d 1199 } else if (S_ISDIR(file->st.st_mode))
71f6f465
MT
1200 file->class |= PAKFIRE_FILE_DIRECTORY;
1201
1202 // Check for symlinks
1203 else if (S_ISLNK(file->st.st_mode))
1204 file->class |= PAKFIRE_FILE_SYMLINK;
1205
1206 // Check for character devices
1207 else if (S_ISCHR(file->st.st_mode))
1208 file->class |= PAKFIRE_FILE_CHARACTER;
1209
1210 // Check for block devices
1211 else if (S_ISBLK(file->st.st_mode))
1212 file->class |= PAKFIRE_FILE_BLOCK;
1213
1214 // Check for FIFO pipes
1215 else if (S_ISFIFO(file->st.st_mode))
1216 file->class |= PAKFIRE_FILE_FIFO;
1217
1218 // Check for sockets
1219 else if (S_ISSOCK(file->st.st_mode))
1220 file->class |= PAKFIRE_FILE_SOCKET;
1221
1222 return 0;
1223}
1224
239230c2
MT
1225static const struct pattern {
1226 const char* pattern;
71f6f465 1227 int class;
239230c2 1228} patterns[] = {
d0831491
MT
1229 { "*.a", PAKFIRE_FILE_STATIC_LIBRARY },
1230 { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE },
71f6f465
MT
1231 { "*.pm", PAKFIRE_FILE_PERL },
1232 { "*.pc", PAKFIRE_FILE_PKGCONFIG },
ec95c0c4 1233 { "/usr/lib/firmware/*", PAKFIRE_FILE_FIRMWARE },
fc35e5cc 1234 { "/usr/lib*/ld-*.so*", PAKFIRE_FILE_RUNTIME_LINKER },
239230c2 1235 { NULL },
71f6f465
MT
1236};
1237
239230c2
MT
1238static int pakfire_file_classify_pattern(struct pakfire_file* file) {
1239 for (const struct pattern* p = patterns; p->pattern; p++) {
1240 if (pakfire_file_matches(file, p->pattern)) {
1241 file->class |= p->class;
71f6f465
MT
1242 break;
1243 }
1244 }
1245
1246 return 0;
1247}
1248
1249static const struct mimetype {
1250 const char* mimetype;
1251 int class;
1252} mimetypes[] = {
71f6f465
MT
1253 { "text/x-perl", PAKFIRE_FILE_PERL },
1254 { NULL, 0 },
1255};
1256
1257static int pakfire_file_classify_magic(struct pakfire_file* file) {
210aabe9
MT
1258 int r;
1259
210aabe9
MT
1260 // Detect the MIME type
1261 r = pakfire_file_detect_mimetype(file);
1262 if (r)
1263 return r;
71f6f465 1264
210aabe9
MT
1265 // Fetch the MIME type
1266 const char* mimetype = pakfire_file_get_mimetype(file);
1267 if (!mimetype)
71f6f465 1268 return 1;
71f6f465 1269
210aabe9 1270 // Match the MIME type with a flag
71f6f465
MT
1271 for (const struct mimetype* m = mimetypes; m->mimetype; m++) {
1272 if (strcmp(m->mimetype, mimetype) == 0) {
1273 file->class |= m->class;
1274 break;
1275 }
1276 }
1277
1278 return 0;
1279}
1280
df71dc60
MT
1281static int pakfire_file_classify_elf(struct pakfire_file* file) {
1282 FILE* f = NULL;
1283 Elf* elf = NULL;
1284 int r;
1285
1286 // Don't run this if we already know that file is an ELF file
1287 if (file->class & PAKFIRE_FILE_ELF)
1288 return 0;
1289
1290 // Setup libelf
1291 r = setup_libelf(file->pakfire);
1292 if (r)
1293 return r;
1294
1295 // Open the file
1296 f = fopen(file->abspath, "r");
1297 if (!f) {
1298 ERROR(file->pakfire, "Could not open %s: %m\n", file->path);
1299 return 1;
1300 }
1301
1302 // Try to open the ELF file
1303 elf = elf_begin(fileno(f), ELF_C_READ, NULL);
1304 if (!elf) {
1305 // We fail silently here, because this file might be in a different format
1306 goto ERROR;
1307 }
1308
1309 switch (elf_kind(elf)) {
1310 // Mark this file as an ELF file
1311 case ELF_K_ELF:
1312 file->class |= PAKFIRE_FILE_ELF;
1313 break;
1314
1315 // Ignore everything else
1316 default:
1317 break;
1318 }
1319
1320ERROR:
1321 if (elf)
1322 elf_end(elf);
1323 if (f)
1324 fclose(f);
1325
1326 return 0;
1327}
1328
71f6f465
MT
1329int pakfire_file_classify(struct pakfire_file* file) {
1330 int r;
1331
1332 if (!file->class) {
1333 // First, check the mode so that we won't run magic on directories, symlinks, ...
1334 r = pakfire_file_classify_mode(file);
1335 if (r)
1336 goto ERROR;
1337
1338 // Only run this for regular files
1339 if (file->class & PAKFIRE_FILE_REGULAR) {
239230c2
MT
1340 // Then check for patterns
1341 r = pakfire_file_classify_pattern(file);
71f6f465
MT
1342 if (r)
1343 goto ERROR;
1344
1345 // After that, we will use libmagic...
1346 r = pakfire_file_classify_magic(file);
1347 if (r)
df71dc60
MT
1348 goto ERROR;
1349
1350 // Check if the file is an ELF file
1351 r = pakfire_file_classify_elf(file);
1352 if (r)
71f6f465
MT
1353 goto ERROR;
1354 }
1355 }
1356
1357 return file->class;
1358
1359ERROR:
1360 // Reset the class
1361 file->class = PAKFIRE_FILE_UNKNOWN;
1362
1363 return r;
1364}
1365
1366int pakfire_file_matches_class(struct pakfire_file* file, const int class) {
1367 return pakfire_file_classify(file) & class;
1368}
1369
ac71886a
MT
1370/*
1371 This function tries to remove the file after it has been packaged.
1372
1373 It will try to delete any parent directories as well and ignore if directories
1374 cannot be deleted because they might contain other files
1375*/
1376int pakfire_file_cleanup(struct pakfire_file* file) {
1377 char path[PATH_MAX];
1378
1379 // Try removing the file
1380 int r = pakfire_file_remove(file);
1381 if (r)
1382 return r;
1383
3fca5032
MT
1384 // Create a working copy of abspath
1385 r = pakfire_string_set(path, file->abspath);
a60955af 1386 if (r)
3fca5032
MT
1387 return r;
1388
1389 // See how many levels this file has
1390 int levels = pakfire_file_levels(file);
1391
1392 // Walk all the way up and remove all parent directories if possible
1393 while (--levels) {
1394 dirname(path);
1395
1396 // Break if path is suddenly empty
1397 if (!*path)
1398 break;
1399
a8783709
MT
1400 DEBUG(file->pakfire, "Trying to remove parent directory %s\n", path);
1401
3fca5032 1402 r = rmdir(path);
3fca5032 1403
a8783709
MT
1404 // Break on any error
1405 if (r)
1406 break;
3fca5032
MT
1407 }
1408
a942166c 1409 return 0;
3fca5032 1410}
cf9bd6f4 1411
9e09e361 1412static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat* st) {
a09b95e0
MT
1413 const mode_t type = pakfire_file_get_type(file);
1414
9e09e361 1415 // Did the type change?
a09b95e0 1416 if (type != (st->st_mode & S_IFMT)) {
9e09e361
MT
1417 file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED;
1418
1419 DEBUG(file->pakfire, "%s: File Type changed\n", file->path);
1420 }
1421
a09b95e0
MT
1422 const mode_t perms = pakfire_file_get_perms(file);
1423
9e09e361 1424 // Check permissions
a09b95e0 1425 if (perms != (st->st_mode & 0777)) {
9e09e361
MT
1426 file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED;
1427
1428 DEBUG(file->pakfire, "%s: Permissions changed\n", file->path);
1429 }
1430
f8733b31
MT
1431#if 0
1432 // XXX This does not check what it is supposed to check
1433
9e09e361
MT
1434 // Check if device node changed
1435 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
a09b95e0
MT
1436 const dev_t dev = pakfire_file_get_dev(file);
1437
1438 if (dev != st->st_dev) {
9e09e361
MT
1439 file->verify_status |= PAKFIRE_FILE_DEV_CHANGED;
1440
1441 DEBUG(file->pakfire, "%s: Device Node changed\n", file->path);
1442 }
1443 }
f8733b31 1444#endif
9e09e361
MT
1445
1446 return 0;
1447}
1448
c0b051bb
MT
1449static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) {
1450 // Nothing to do if size matches
a09b95e0 1451 if (file->st.st_size == st->st_size)
c0b051bb
MT
1452 return 0;
1453
1454 // Size differs
d2b0e219 1455 file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED;
c0b051bb
MT
1456
1457 DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
a09b95e0 1458 file->path, file->st.st_size, st->st_size);
c0b051bb
MT
1459
1460 return 0;
1461}
1462
1463static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct stat* st) {
1464 // Fetch UID/GID
1465#if 0
1466 const uid_t uid = pakfire_unmap_id(file->pakfire, st->st_uid);
1467 const gid_t gid = pakfire_unmap_id(file->pakfire, st->st_gid);
1468#else
1469 const uid_t uid = st->st_uid;
1470 const gid_t gid = st->st_gid;
1471#endif
1472
1473 // Fetch owner & group
302e3253
MT
1474 struct passwd* owner = pakfire_getpwnam(file->pakfire, file->uname);
1475 struct group* group = pakfire_getgrnam(file->pakfire, file->gname);
c0b051bb
MT
1476
1477 // Check if owner matches
1478 if (!owner || owner->pw_uid != uid) {
d2b0e219 1479 file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED;
c0b051bb
MT
1480
1481 DEBUG(file->pakfire, "%s: Owner differs\n", file->path);
1482 }
1483
1484 // Check if group matches
1485 if (!group || group->gr_gid != gid) {
d2b0e219 1486 file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED;
c0b051bb
MT
1487
1488 DEBUG(file->pakfire, "%s: Group differs\n", file->path);
1489 }
1490
1491 return 0;
1492}
1493
0eeac4a5
MT
1494static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) {
1495 // Check creation time
a09b95e0 1496 if (file->st.st_ctime != st->st_ctime) {
0eeac4a5
MT
1497 file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED;
1498
1499 DEBUG(file->pakfire, "%s: Creation time changed\n", file->path);
1500 }
1501
1502 // Check modification time
a09b95e0 1503 if (file->st.st_mtime != st->st_mtime) {
0eeac4a5
MT
1504 file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED;
1505
1506 DEBUG(file->pakfire, "%s: Modification time changed\n", file->path);
1507 }
1508
1509 return 0;
1510}
1511
76011205 1512static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) {
76011205
MT
1513 int r;
1514
c52e0148 1515 struct pakfire_digests computed_digests;
293881bc 1516 int digest_types = PAKFIRE_DIGEST_UNDEFINED;
76011205
MT
1517
1518 // Nothing to do for anything that isn't a regular file
1519 if (!S_ISREG(st->st_mode))
1520 return 0;
1521
1522 // Fast-path if size changed. The payload will have changed, too
1523 if (file->verify_status & PAKFIRE_FILE_SIZE_CHANGED) {
1524 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
1525 return 0;
1526 }
1527
1528 // Check if this file has any digests at all
6b32db11 1529 digest_types = pakfire_digest_has_any(&file->digests);
76011205 1530
293881bc
MT
1531 if (!digest_types) {
1532 ERROR(file->pakfire, "%s: No digests available\n", file->path);
1533 return 0;
76011205
MT
1534 }
1535
293881bc 1536 // Compute digests
1e76689a 1537 r = __pakfire_file_compute_digests(file, &computed_digests, digest_types);
293881bc 1538 if (r)
76011205 1539 goto ERROR;
76011205 1540
293881bc
MT
1541 // Compare digests
1542 r = pakfire_digests_compare(file->pakfire, &file->digests, &computed_digests, digest_types);
76011205
MT
1543 if (r) {
1544 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
1545
293881bc 1546 DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path);
76011205
MT
1547 }
1548
76011205 1549ERROR:
76011205
MT
1550 return r;
1551}
1552
cf9bd6f4
MT
1553/*
1554 Verify the file - i.e. does the metadata match what is on disk?
1555*/
c0b051bb
MT
1556int pakfire_file_verify(struct pakfire_file* file, int* status) {
1557 struct stat st;
1558 int r;
1559
cf9bd6f4
MT
1560 DEBUG(file->pakfire, "Verifying %s...\n", file->path);
1561
c0b051bb
MT
1562 // stat() the file
1563 r = lstat(file->abspath, &st);
1564 if (r) {
1565 // File does not exist
1566 if (errno == ENOENT) {
1567 file->verify_status |= PAKFIRE_FILE_NOENT;
1568 return 1;
1569 }
1570
1571 // Raise any other errors from stat()
1572 return r;
1573 }
1574
9e09e361
MT
1575 // Verify mode
1576 r = pakfire_file_verify_mode(file, &st);
1577 if (r)
1578 return r;
1579
c0b051bb
MT
1580 // Verify size
1581 r = pakfire_file_verify_size(file, &st);
1582 if (r)
1583 return r;
1584
1585 // Verify ownership
1586 r = pakfire_file_verify_ownership(file, &st);
1587 if (r)
1588 return r;
1589
0eeac4a5
MT
1590 // Verify timestamps
1591 r = pakfire_file_verify_timestamps(file, &st);
1592 if (r)
1593 return r;
1594
76011205
MT
1595 // Verify payload
1596 r = pakfire_file_verify_payload(file, &st);
1597 if (r)
1598 return r;
1599
cf9bd6f4
MT
1600 return 0;
1601}
c064d9ec
MT
1602
1603PAKFIRE_EXPORT int pakfire_file_matches(struct pakfire_file* file, const char* pattern) {
1604 int r;
1605
1606 // Don't match on no pattern
1607 if (!pattern)
1608 return 0;
1609
1610 // Check if the pattern matches
1611 r = fnmatch(pattern, file->path, 0);
1612 switch (r) {
1613 // Match
1614 case 0:
1615 return 1;
1616
1617 // No Match
1618 case FNM_NOMATCH:
1619 return 0;
1620
1621 default:
1622 return -1;
1623 }
1624}
2dcb43e7
MT
1625
1626/*
1627 ELF Stuff
1628*/
1629
1630static int pakfire_file_open_elf(struct pakfire_file* file,
1631 int (*callback)(struct pakfire_file* file, Elf* elf, void* data), void* data) {
1632 FILE* f = NULL;
1633 Elf* elf = NULL;
1634 int r;
1635
1636 // Don't run this for non-ELF files
1637 if (!pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
1638 errno = EINVAL;
1639 return 1;
1640 }
1641
1642 // Setup libelf
1643 r = setup_libelf(file->pakfire);
1644 if (r)
1645 return r;
1646
1647 // Open the file
1648 f = fopen(file->abspath, "r");
1649 if (!f) {
1650 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
1651 return 1;
1652 }
1653
1654 // Parse the ELF header
1655 elf = elf_begin(fileno(f), ELF_C_READ, NULL);
1656 if (!elf) {
1657 ERROR(file->pakfire, "Could not open ELF file: %s\n", elf_errmsg(-1));
1658 r = 1;
1659 goto ERROR;
1660 }
1661
1662 // Check if this is an ELF file
1663 switch (elf_kind(elf)) {
1664 case ELF_K_ELF:
1665 break;
1666
1667 default:
1668 ERROR(file->pakfire, "%s is not an ELF object\n", file->path);
1669 r = 1;
1670 goto ERROR;
1671 }
1672
1673 // Call the callback
1674 r = callback(file, elf, data);
1675
1676ERROR:
1677 if (elf)
1678 elf_end(elf);
1679 if (f)
1680 fclose(f);
1681
1682 return r;
1683}
1684
e9d5d508
MT
1685static int pakfire_file_get_elf_section(struct pakfire_file* file,
1686 Elf* elf, const Elf64_Word type, Elf_Scn** section, GElf_Shdr* header, Elf_Data** data) {
1687 Elf_Scn* s = NULL;
1688
0ef20579
MT
1689 GElf_Shdr shdr;
1690
1691 // Walk through all sections
1692 for (;;) {
e9d5d508
MT
1693 s = elf_nextscn(elf, s);
1694 if (!s)
0ef20579
MT
1695 break;
1696
1697 // Fetch the section header
e9d5d508 1698 gelf_getshdr(s, &shdr);
0ef20579
MT
1699
1700 // Return any matching sections
e9d5d508
MT
1701 if (shdr.sh_type == type) {
1702 *section = s;
1703
1704 // Send header if requested
1705 if (header)
1706 gelf_getshdr(s, header);
1707
1708 // Send data if requested
1709 if (data)
1710 *data = elf_getdata(s, NULL);
1711
1712 return 0;
1713 }
0ef20579
MT
1714 }
1715
1716 // No section found
e9d5d508 1717 return 1;
0ef20579
MT
1718}
1719
8a385eff
MT
1720static int __pakfire_file_get_elf_type(struct pakfire_file* file, Elf* elf, void* data) {
1721 int* type = (int*)data;
1722 GElf_Ehdr ehdr;
1723
1724 // Fetch the ELF header
1725 if (!gelf_getehdr(elf, &ehdr)) {
1726 ERROR(file->pakfire, "Could not parse ELF header: %s\n", elf_errmsg(-1));
1727 return 1;
1728 }
1729
1730 // Store the type
1731 *type = ehdr.e_type;
1732
1733 return 0;
1734}
1735
1736static int pakfire_file_get_elf_type(struct pakfire_file* file) {
1737 int type = ET_NONE;
1738 int r;
1739
1740 r = pakfire_file_open_elf(file, __pakfire_file_get_elf_type, &type);
1741 if (r)
1742 return -1;
1743
1744 return type;
1745}
1746
7b461c8b
MT
1747static int pakfire_file_elf_dyn_walk(struct pakfire_file* file, Elf* elf,
1748 int (*callback)(struct pakfire_file* file, Elf64_Word key, const char* value, void* data),
1749 void* data) {
1750 Elf_Scn* dynamic = NULL;
1751 GElf_Shdr shdr;
1752 Elf_Data* elf_data = NULL;
1753 int r;
1754
1755 // Find the dynamic linking information
1756 r = pakfire_file_get_elf_section(file, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data);
1757 if (r) {
1758 ERROR(file->pakfire, "%s does not have a dynamic section\n", file->path);
1759 return 1;
1760 }
1761
1762 GElf_Dyn dyn;
1763 const char* value = NULL;
1764
1765 // Walk through all entries...
1766 for (unsigned int i = 0; ; i++) {
1767 // Fetch the next entry
1768 if (!gelf_getdyn(elf_data, i, &dyn))
1769 break;
1770
1771 // Fetch the value
1772 value = elf_strptr(elf, shdr.sh_link, dyn.d_un.d_val);
1773
1774 // Call the callback
1775 r = callback(file, dyn.d_tag, value, data);
1776 if (r)
1777 return r;
1778 }
1779
1780 return 0;
1781}
1782
03a5ac95 1783static int __pakfire_file_check_debuginfo(struct pakfire_file* file, Elf* elf, void* data) {
e9d5d508
MT
1784 Elf_Scn* symtab = NULL;
1785 int r;
1786
0ef20579 1787 // Fetch the symbol table
e9d5d508 1788 r = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB, &symtab, NULL, NULL);
8e8de3c1
MT
1789
1790 // Not found
e9d5d508 1791 if (r) {
0ef20579 1792 DEBUG(file->pakfire, "%s has no debug sections\n", file->path);
8e8de3c1 1793
0ef20579
MT
1794 // Store the result
1795 file->issues |= PAKFIRE_FILE_MISSING_DEBUGINFO;
1796 }
8e8de3c1 1797
03a5ac95
MT
1798 return 0;
1799}
ec95c0c4 1800
03a5ac95 1801static int pakfire_file_check_debuginfo(struct pakfire_file* file) {
8a385eff
MT
1802 switch (pakfire_file_get_elf_type(file)) {
1803 // Do not check Relocatable Objects
1804 case ET_REL:
1805 return 0;
1806
1807 // Check everything else
1808 default:
1809 break;
1810 }
1811
03a5ac95 1812 return pakfire_file_open_elf(file, __pakfire_file_check_debuginfo, NULL);
8e8de3c1
MT
1813}
1814
28886e21 1815static int __pakfire_file_check_ssp(
2dcb43e7 1816 struct pakfire_file* file, Elf* elf, void* data) {
0ef20579
MT
1817 Elf_Scn* symtab = NULL;
1818 GElf_Shdr shdr;
2dcb43e7
MT
1819 Elf_Data* elf_data = NULL;
1820 GElf_Sym symbol;
1821 const char* name = NULL;
e9d5d508 1822 int r;
2dcb43e7 1823
0ef20579 1824 // Fetch the symbol table
e9d5d508
MT
1825 r = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB, &symtab, &shdr, &elf_data);
1826 if (r) {
0ef20579
MT
1827 ERROR(file->pakfire, "%s has no symbol table\n", file->path);
1828 return 1;
1829 }
2dcb43e7 1830
0ef20579
MT
1831 // Count any global functions
1832 size_t counter = 0;
2dcb43e7 1833
2dcb43e7 1834 // Walk through all symbols
0ef20579 1835 for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
2dcb43e7
MT
1836 gelf_getsym(elf_data, i, &symbol);
1837
1838 // Fetch the symbol name
0ef20579 1839 name = elf_strptr(elf, shdr.sh_link, symbol.st_name);
2dcb43e7
MT
1840
1841 // Skip empty section names
1842 if (!name || !*name)
1843 continue;
1844
f7f44921 1845 // Exit if there is a symbol called "__stack_chk_fail"
2dcb43e7 1846 if (pakfire_string_startswith(name, "__stack_chk_fail"))
f7f44921 1847 return 0;
0f7c90ef
MT
1848
1849 // Count any global functions
1850 if ((ELF64_ST_BIND(symbol.st_info) == STB_GLOBAL) &&
1851 (ELF64_ST_TYPE(symbol.st_info) == STT_FUNC))
1852 counter++;
1853 }
1854
1855 // We do not perform the check for libraries that do not contain any functions.
1856 // Some packages use shared libraries to provide data.
1857 if (!counter) {
1858 DEBUG(file->pakfire, "%s: File has no functions. Skipping SSP check.\n", file->path);
1859 return 0;
2dcb43e7
MT
1860 }
1861
f7f44921 1862 // The file does not seem to have SSP enabled
d8acc837 1863 file->issues |= PAKFIRE_FILE_MISSING_SSP;
f7f44921 1864
2dcb43e7
MT
1865 return 0;
1866}
1867
28886e21 1868static int pakfire_file_check_ssp(struct pakfire_file* file) {
fc35e5cc
MT
1869 // Do not perform this check for runtime linkers
1870 if (pakfire_file_matches_class(file, PAKFIRE_FILE_RUNTIME_LINKER))
1871 return 0;
1872
03a5ac95
MT
1873 // We cannot perform this check if we don't have debuginfo
1874 if (file->issues & PAKFIRE_FILE_MISSING_DEBUGINFO)
1875 return 0;
1876
28886e21 1877 return pakfire_file_open_elf(file, __pakfire_file_check_ssp, NULL);
2dcb43e7 1878}
2a67d72c 1879
28886e21 1880static int pakfire_file_check_pie(struct pakfire_file* file) {
8a385eff
MT
1881 switch (pakfire_file_get_elf_type(file)) {
1882 // Shared Object files are good
2a67d72c 1883 case ET_DYN:
22e696bd 1884 break;
2a67d72c 1885
8a385eff 1886 // Everything else is bad
2a67d72c 1887 default:
d8acc837 1888 file->issues |= PAKFIRE_FILE_MISSING_PIE;
22e696bd 1889 break;
2a67d72c 1890 }
22e696bd
MT
1891
1892 return 0;
f7f44921
MT
1893}
1894
28886e21 1895static int __pakfire_file_check_execstack(
dae43e1f
MT
1896 struct pakfire_file* file, Elf* elf, void* data) {
1897 GElf_Phdr phdr;
1898 int r;
1899
1900 size_t phnum = 0;
1901
1902 // Fetch the total numbers of program headers
1903 r = elf_getphdrnum(elf, &phnum);
1904 if (r) {
1905 ERROR(file->pakfire, "Could not fetch number of program headers: %s\n",
1906 elf_errmsg(-1));
1907 return 1;
1908 }
1909
1910 // Walk through all program headers
1911 for (unsigned int i = 0; i < phnum; i++) {
1912 if (!gelf_getphdr(elf, i, &phdr)) {
1913 ERROR(file->pakfire, "Could not parse program header: %s\n", elf_errmsg(-1));
1914 return 1;
1915 }
1916
1917 switch (phdr.p_type) {
1918 case PT_GNU_STACK:
1919 DEBUG(file->pakfire,
1920 "%s: GNU_STACK flags: %c%c%c\n",
1921 file->path,
1922 (phdr.p_flags & PF_R) ? 'R' : '-',
1923 (phdr.p_flags & PF_W) ? 'W' : '-',
1924 (phdr.p_flags & PF_X) ? 'X' : '-'
1925 );
1926
1927 // The stack cannot be writable and executable
1928 if ((phdr.p_flags & PF_W) && (phdr.p_flags & PF_X))
28886e21 1929 file->issues |= PAKFIRE_FILE_EXECSTACK;
dae43e1f
MT
1930
1931 // Done
1932 return 0;
1933
1934 default:
1935 break;
1936 }
1937 }
1938
1939 return 0;
1940}
1941
28886e21
MT
1942static int pakfire_file_check_execstack(struct pakfire_file* file) {
1943 return pakfire_file_open_elf(file, __pakfire_file_check_execstack, NULL);
dae43e1f
MT
1944}
1945
28886e21 1946static int __pakfire_file_check_partially_relro(
d265bed6
MT
1947 struct pakfire_file* file, Elf* elf, void* data) {
1948 GElf_Phdr phdr;
1949 int r;
1950
1951 size_t phnum = 0;
1952
1953 // Fetch the total numbers of program headers
1954 r = elf_getphdrnum(elf, &phnum);
1955 if (r) {
1956 ERROR(file->pakfire, "Could not fetch number of program headers: %s\n",
1957 elf_errmsg(-1));
1958 return 1;
1959 }
1960
1961 // Walk through all program headers
1962 for (unsigned int i = 0; i < phnum; i++) {
1963 if (!gelf_getphdr(elf, i, &phdr)) {
1964 ERROR(file->pakfire, "Could not parse program header: %s\n", elf_errmsg(-1));
1965 return 1;
1966 }
1967
1968 switch (phdr.p_type) {
1969 case PT_GNU_RELRO:
1970 return 0;
1971
1972 default:
1973 break;
1974 }
1975 }
1976
1977 // This file does not seem to have PT_GNU_RELRO set
28886e21 1978 file->issues |= PAKFIRE_FILE_NO_PARTIALLY_RELRO;
d265bed6
MT
1979
1980 return 0;
1981}
1982
28886e21
MT
1983static int pakfire_file_check_relro(struct pakfire_file* file) {
1984 return pakfire_file_open_elf(file, __pakfire_file_check_partially_relro, NULL);
d265bed6
MT
1985}
1986
7b461c8b
MT
1987/*
1988 RPATH/RUNPATH
1989*/
1990static int __pakfire_file_process_runpath(struct pakfire_file* file,
1991 Elf64_Word key, const char* value, void* data) {
1992 const char* runpath = NULL;
1993 char buffer[PATH_MAX];
1994 char* p = NULL;
1995 int r;
1996
1997 switch (key) {
1998 case DT_RUNPATH:
1999 case DT_RPATH:
2000 DEBUG(file->pakfire, "%s has a RUNPATH: %s\n", file->path, value);
2001
2002 // Copy the value into a buffer we can modify
2003 r = pakfire_string_set(buffer, value);
2004 if (r)
2005 return r;
2006
2007 // Split the value by :
2008 runpath = strtok_r(buffer, ":", &p);
2009
2010 // Iterate over all elements
2011 while (runpath) {
2012 DEBUG(file->pakfire, "Checking RUNPATH %s\n", runpath);
2013
2014 // We do not allow any relative RUNPATHs
2015 if (pakfire_path_match(runpath, "**/../**")) {
2016 file->issues |= PAKFIRE_FILE_HAS_RUNPATH;
2017 break;
2018 }
2019
2020 /*
2021 We allow some RUNPATHs where some software is loading some
2022 modules as shared objects from a private directory in /usr/lib64.
2023 */
2024 if (!pakfire_path_match(runpath, "/usr/lib64")
2025 && !pakfire_path_match(runpath, "/usr/lib64/**")) {
2026 file->issues |= PAKFIRE_FILE_HAS_RUNPATH;
2027 break;
2028 }
2029
2030 // Move on to the next RUNPATH
2031 runpath = strtok_r(NULL, ":", &p);
2032 }
2033
2034 default:
2035 break;
2036 }
2037
2038 return 0;
2039}
2040
2041static int __pakfire_file_check_runpath(struct pakfire_file* file, Elf* elf, void* data) {
2042 return pakfire_file_elf_dyn_walk(file, elf, __pakfire_file_process_runpath, data);
2043}
2044
2045static int pakfire_file_check_runpath(struct pakfire_file* file) {
2046 return pakfire_file_open_elf(file, __pakfire_file_check_runpath, NULL);
2047}
d265bed6 2048
28886e21 2049int pakfire_file_check(struct pakfire_file* file, int* issues) {
f7f44921
MT
2050 int r;
2051
2052 // Return previous result if this has been run before
28886e21 2053 if (!file->check_done) {
6d9dd7bc
MT
2054 // Perform FHS check
2055 r = pakfire_fhs_check_file(file->pakfire, file);
2056 if (r)
28886e21 2057 file->issues |= PAKFIRE_FILE_FHS_ERROR;
8a385eff 2058
6d9dd7bc
MT
2059 // Do not perform the following checks on firmware
2060 if (pakfire_file_matches_class(file, PAKFIRE_FILE_FIRMWARE))
2061 goto DONE;
8a385eff 2062
6d9dd7bc
MT
2063 // Run these checks only for ELF files
2064 if (pakfire_file_matches_class(file, PAKFIRE_FILE_ELF)) {
2065 switch (pakfire_file_get_elf_type(file)) {
2066 // Do not check Relocatable Objects
2067 case ET_REL:
2068 goto DONE;
2069
2070 // Check everything else
2071 default:
2072 break;
2073 }
f7f44921 2074
03a5ac95
MT
2075 // Check if the file has debug info
2076 r = pakfire_file_check_debuginfo(file);
2077 if (r)
2078 return r;
2079
6d9dd7bc 2080 // Check for SSP
28886e21 2081 r = pakfire_file_check_ssp(file);
6d9dd7bc
MT
2082 if (r)
2083 return r;
f7f44921 2084
6d9dd7bc 2085 // Check for PIE
28886e21 2086 r = pakfire_file_check_pie(file);
6d9dd7bc
MT
2087 if (r)
2088 return r;
dae43e1f 2089
6d9dd7bc 2090 // Check for executable stacks
28886e21 2091 r = pakfire_file_check_execstack(file);
6d9dd7bc
MT
2092 if (r)
2093 return r;
2094
2095 // Check for RELRO
28886e21 2096 r = pakfire_file_check_relro(file);
6d9dd7bc
MT
2097 if (r)
2098 return r;
7b461c8b
MT
2099
2100 // Check for RUNPATH
2101 r = pakfire_file_check_runpath(file);
2102 if (r)
2103 return r;
6d9dd7bc 2104 }
d265bed6 2105
8a385eff 2106DONE:
f7f44921 2107 // All checks done
28886e21 2108 file->check_done = 1;
f7f44921
MT
2109 }
2110
2111 // Return any issues
2112 if (issues)
28886e21 2113 *issues = file->issues;
f7f44921
MT
2114
2115 return 0;
2a67d72c 2116}