1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2014 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
25 #include <linux/limits.h>
29 #include <sys/types.h>
32 #include <archive_entry.h>
36 #include <pakfire/constants.h>
37 #include <pakfire/digest.h>
38 #include <pakfire/file.h>
39 #include <pakfire/logging.h>
40 #include <pakfire/pakfire.h>
41 #include <pakfire/private.h>
42 #include <pakfire/string.h>
43 #include <pakfire/util.h>
45 enum pakfire_file_verification_status
{
46 PAKFIRE_FILE_NOENT
= (1 << 0),
47 PAKFIRE_FILE_TYPE_CHANGED
= (1 << 1),
48 PAKFIRE_FILE_PERMISSIONS_CHANGED
= (1 << 2),
49 PAKFIRE_FILE_DEV_CHANGED
= (1 << 3),
50 PAKFIRE_FILE_SIZE_CHANGED
= (1 << 4),
51 PAKFIRE_FILE_OWNER_CHANGED
= (1 << 5),
52 PAKFIRE_FILE_GROUP_CHANGED
= (1 << 6),
53 PAKFIRE_FILE_CTIME_CHANGED
= (1 << 7),
54 PAKFIRE_FILE_MTIME_CHANGED
= (1 << 8),
55 PAKFIRE_FILE_PAYLOAD_CHANGED
= (1 << 9),
59 struct pakfire
* pakfire
;
65 // The absolute path in the file system
66 char abspath
[PATH_MAX
];
69 char uname
[LOGIN_NAME_MAX
];
70 char gname
[LOGIN_NAME_MAX
];
79 char hardlink
[PATH_MAX
];
80 char symlink
[PATH_MAX
];
83 struct pakfire_digests digests
;
86 char mimetype
[NAME_MAX
];
91 // Verification Status
96 int hardening_check_done
:1;
98 #warning TODO capabilities, data
103 static int pakfire_file_from_archive_entry(struct pakfire_file
* file
, struct archive_entry
* entry
) {
105 const char* path
= NULL
;
106 const char* attr
= NULL
;
107 const void* value
= NULL
;
112 path
= archive_entry_sourcepath(entry
);
114 // Make path absolute
115 path
= pakfire_path_abspath(path
);
122 r
= pakfire_file_set_abspath(file
, path
);
124 ERROR(file
->pakfire
, "Could not set abspath: %m\n");
130 path
= archive_entry_pathname(entry
);
132 r
= pakfire_file_set_path(file
, path
);
134 ERROR(file
->pakfire
, "Could not set path: %m\n");
140 pakfire_file_set_hardlink(file
, archive_entry_hardlink(entry
));
141 pakfire_file_set_symlink(file
, archive_entry_symlink(entry
));
143 pakfire_file_set_nlink(file
, archive_entry_nlink(entry
));
144 pakfire_file_set_inode(file
, archive_entry_ino64(entry
));
145 pakfire_file_set_dev(file
, archive_entry_dev(entry
));
148 pakfire_file_set_size(file
, archive_entry_size(entry
));
151 pakfire_file_set_mode(file
, archive_entry_mode(entry
));
154 if (archive_entry_dev_is_set(entry
))
155 pakfire_file_set_dev(file
, archive_entry_dev(entry
));
158 pakfire_file_set_uname(file
, archive_entry_uname(entry
));
161 pakfire_file_set_gname(file
, archive_entry_gname(entry
));
164 pakfire_file_set_ctime(file
, archive_entry_ctime(entry
));
165 pakfire_file_set_mtime(file
, archive_entry_mtime(entry
));
167 // Reset iterating over extended attributes
168 archive_entry_xattr_reset(entry
);
170 // Read any extended attributes
171 while (archive_entry_xattr_next(entry
, &attr
, &value
, &size
) == ARCHIVE_OK
) {
173 if (strcmp(attr
, "PAKFIRE.config") == 0) {
174 r
= pakfire_file_set_flags(file
, PAKFIRE_FILE_CONFIG
);
179 } else if (strcmp(attr
, "PAKFIRE.mimetype") == 0) {
180 // Copy the value into a NULL-terminated buffer
181 r
= asprintf(&buffer
, "%.*s", (int)size
, (const char*)value
);
186 r
= pakfire_file_set_mimetype(file
, buffer
);
191 } else if (strcmp(attr
, "PAKFIRE.digests.sha3_512") == 0) {
192 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA3_512
, value
, size
);
197 } else if (strcmp(attr
, "PAKFIRE.digests.sha3_256") == 0) {
198 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA3_256
, value
, size
);
202 // Digest: BLAKE2b512
203 } else if (strcmp(attr
, "PAKFIRE.digests.blake2b512") == 0) {
204 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_BLAKE2B512
, value
, size
);
208 // Digest: BLAKE2s256
209 } else if (strcmp(attr
, "PAKFIRE.digests.blake2s256") == 0) {
210 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_BLAKE2S256
, value
, size
);
215 } else if (strcmp(attr
, "PAKFIRE.digests.sha2_512") == 0) {
216 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA2_512
, value
, size
);
221 } else if (strcmp(attr
, "PAKFIRE.digests.sha2_256") == 0) {
222 r
= pakfire_file_set_digest(file
, PAKFIRE_DIGEST_SHA2_256
, value
, size
);
227 DEBUG(file
->pakfire
, "Received an unknown extended attribute: %s\n", attr
);
238 PAKFIRE_EXPORT
int pakfire_file_create(struct pakfire_file
** file
, struct pakfire
* pakfire
) {
239 struct pakfire_file
* f
= calloc(1, sizeof(*f
));
243 // Store reference to Pakfire
244 f
->pakfire
= pakfire_ref(pakfire
);
246 // Initialize reference counter
253 int pakfire_file_create_from_path(struct pakfire_file
** file
,
254 struct pakfire
* pakfire
, const char* path
) {
255 struct archive
* reader
= NULL
;
256 struct archive_entry
* entry
= NULL
;
260 reader
= pakfire_make_archive_disk_reader(pakfire
, 0);
264 // Allocate a new archive entry
265 entry
= archive_entry_new();
270 archive_entry_copy_sourcepath(entry
, path
);
272 // Read all file attributes from disk
273 r
= archive_read_disk_entry_from_file(reader
, entry
, -1, NULL
);
275 ERROR(pakfire
, "Could not read from %s: %m\n", path
);
280 r
= pakfire_file_create_from_archive_entry(file
, pakfire
, entry
);
286 ERROR(pakfire
, "Could not create file from path %s: %m\n", path
);
288 archive_entry_free(entry
);
290 archive_read_free(reader
);
295 int pakfire_file_create_from_archive_entry(struct pakfire_file
** file
, struct pakfire
* pakfire
,
296 struct archive_entry
* entry
) {
297 int r
= pakfire_file_create(file
, pakfire
);
301 // Copy archive entry
302 r
= pakfire_file_from_archive_entry(*file
, entry
);
309 pakfire_file_unref(*file
);
315 struct archive_entry
* pakfire_file_archive_entry(struct pakfire_file
* file
, int digest_types
) {
316 const char* path
= NULL
;
319 struct archive_entry
* entry
= archive_entry_new();
321 ERROR(file
->pakfire
, "Could not allocate archive entry: %m\n");
326 archive_entry_copy_sourcepath(entry
, file
->abspath
);
329 path
= pakfire_file_get_path(file
);
330 if (path
&& *path
== '/') {
331 archive_entry_copy_pathname(entry
, path
+ 1);
336 archive_entry_set_hardlink(entry
, file
->hardlink
);
338 archive_entry_set_symlink(entry
, file
->symlink
);
340 archive_entry_set_nlink(entry
, pakfire_file_get_nlink(file
));
341 archive_entry_set_ino64(entry
, pakfire_file_get_inode(file
));
342 archive_entry_set_dev(entry
, pakfire_file_get_dev(file
));
345 archive_entry_set_size(entry
, pakfire_file_get_size(file
));
348 archive_entry_set_mode(entry
, pakfire_file_get_mode(file
));
351 archive_entry_set_uname(entry
, pakfire_file_get_uname(file
));
354 archive_entry_set_gname(entry
, pakfire_file_get_gname(file
));
357 archive_entry_set_ctime(entry
, pakfire_file_get_ctime(file
), 0);
358 archive_entry_set_mtime(entry
, pakfire_file_get_mtime(file
), 0);
361 if (pakfire_file_has_flag(file
, PAKFIRE_FILE_CONFIG
)) {
362 archive_entry_xattr_add_entry(entry
,
363 "PAKFIRE.config", "1", strlen("1"));
367 const char* mimetype
= pakfire_file_get_mimetype(file
);
369 archive_entry_xattr_add_entry(entry
,
370 "PAKFIRE.mimetype", mimetype
, strlen(mimetype
));
373 // Compute any required file digests
374 r
= pakfire_file_compute_digests(file
, digest_types
);
381 if ((digest_types
&& PAKFIRE_DIGEST_SHA3_512
)
382 && pakfire_digest_set(file
->digests
.sha3_512
))
383 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha3_512",
384 file
->digests
.sha3_512
, sizeof(file
->digests
.sha3_512
));
387 if ((digest_types
&& PAKFIRE_DIGEST_SHA3_256
) &&
388 pakfire_digest_set(file
->digests
.sha3_256
))
389 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha3_256",
390 file
->digests
.sha3_256
, sizeof(file
->digests
.sha3_256
));
393 if ((digest_types
&& PAKFIRE_DIGEST_BLAKE2B512
) &&
394 pakfire_digest_set(file
->digests
.blake2b512
))
395 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.blake2b512",
396 file
->digests
.blake2b512
, sizeof(file
->digests
.blake2b512
));
399 if ((digest_types
&& PAKFIRE_DIGEST_BLAKE2S256
) &&
400 pakfire_digest_set(file
->digests
.blake2s256
))
401 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.blake2s256",
402 file
->digests
.blake2s256
, sizeof(file
->digests
.blake2s256
));
405 if ((digest_types
&& PAKFIRE_DIGEST_SHA2_512
) &&
406 pakfire_digest_set(file
->digests
.sha2_512
))
407 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha2_512",
408 file
->digests
.sha2_512
, sizeof(file
->digests
.sha2_512
));
411 if ((digest_types
&& PAKFIRE_DIGEST_SHA2_512
) &&
412 pakfire_digest_set(file
->digests
.sha2_256
))
413 archive_entry_xattr_add_entry(entry
, "PAKFIRE.digests.sha2_256",
414 file
->digests
.sha2_256
, sizeof(file
->digests
.sha2_256
));
420 archive_entry_free(entry
);
425 static void pakfire_file_free(struct pakfire_file
* file
) {
426 pakfire_unref(file
->pakfire
);
430 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_ref(struct pakfire_file
* file
) {
436 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_unref(struct pakfire_file
* file
) {
437 if (--file
->nrefs
> 0)
440 pakfire_file_free(file
);
448 int pakfire_file_has_flag(struct pakfire_file
* file
, int flag
) {
449 return file
->flags
& flag
;
452 int pakfire_file_set_flags(struct pakfire_file
* file
, int flag
) {
458 #define pakfire_file_strmode(file, buffer) \
459 __pakfire_file_strmode(file, buffer, sizeof(buffer))
461 static int __pakfire_file_strmode(struct pakfire_file
* file
, char* s
, const size_t length
) {
464 static const mode_t permbits
[] = {
476 const mode_t mode
= pakfire_file_get_mode(file
);
477 const mode_t type
= pakfire_file_get_type(file
);
479 // Set some default string
480 r
= __pakfire_string_set(s
, length
, "?rwxrwxrwx ");
514 if (*file
->hardlink
) {
520 for (unsigned int i
= 0; i
< 9; i
++) {
521 if (mode
& permbits
[i
])
527 if (mode
& S_ISUID
) {
534 if (mode
& S_ISGID
) {
541 if (mode
& S_ISVTX
) {
556 char* pakfire_file_dump(struct pakfire_file
* file
, int flags
) {
564 if (flags
& PAKFIRE_FILE_DUMP_MODE
) {
565 r
= pakfire_file_strmode(file
, mode
);
569 r
= asprintf(&buffer
, "%s %s", buffer
, mode
);
575 if (flags
& PAKFIRE_FILE_DUMP_OWNERSHIP
) {
576 r
= asprintf(&buffer
, "%s %s/%s", buffer
, file
->uname
, file
->gname
);
582 if (flags
& PAKFIRE_FILE_DUMP_SIZE
) {
583 r
= asprintf(&buffer
, "%s %8zu", buffer
, file
->st
.st_size
);
589 if (flags
& PAKFIRE_FILE_DUMP_TIME
) {
590 r
= pakfire_strftime(time
, "%Y-%m-%d %H:%M", file
->st
.st_ctime
);
594 r
= asprintf(&buffer
, "%s %s", buffer
, time
);
600 r
= asprintf(&buffer
, "%s %s", buffer
, file
->path
);
604 // Append symlink target
605 if (flags
& PAKFIRE_FILE_DUMP_LINK_TARGETS
) {
606 switch (pakfire_file_get_type(file
)) {
608 r
= asprintf(&buffer
, "%s -> %s", buffer
, file
->symlink
);
618 if (flags
& PAKFIRE_FILE_DUMP_HARDENING
) {
619 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
620 // Stack-smashing Protection
621 if (file
->hardening_issues
& PAKFIRE_FILE_NO_SSP
) {
622 r
= asprintf(&buffer
, "%s [NO-SSP]", buffer
);
627 // Position-independent Executable
628 if (file
->hardening_issues
& PAKFIRE_FILE_NO_PIE
) {
629 r
= asprintf(&buffer
, "%s [NO-PIE]", buffer
);
635 if (file
->hardening_issues
& PAKFIRE_FILE_EXECSTACK
) {
636 r
= asprintf(&buffer
, "%s [EXECSTACK]", buffer
);
641 // Not Partially RELRO
642 if (file
->hardening_issues
& PAKFIRE_FILE_NO_PARTIALLY_RELRO
) {
643 r
= asprintf(&buffer
, "%s [NO-PART-RELRO]", buffer
);
659 PAKFIRE_EXPORT
int pakfire_file_cmp(struct pakfire_file
* file1
, struct pakfire_file
* file2
) {
660 const char* path1
= pakfire_file_get_path(file1
);
661 const char* path2
= pakfire_file_get_path(file2
);
663 return strcmp(path1
, path2
);
666 const char* pakfire_file_get_abspath(struct pakfire_file
* file
) {
667 return file
->abspath
;
670 int pakfire_file_set_abspath(struct pakfire_file
* file
, const char* path
) {
673 // Check if path is set and absolute
674 if (!path
|| *path
!= '/') {
680 r
= pakfire_string_set(file
->abspath
, path
);
684 // Store path if it isn't set, yet
686 r
= pakfire_file_set_path(file
, path
);
694 ERROR(file
->pakfire
, "Could not set abspath '%s': %m\n", path
);
698 PAKFIRE_EXPORT
const char* pakfire_file_get_path(struct pakfire_file
* file
) {
702 PAKFIRE_EXPORT
int pakfire_file_set_path(struct pakfire_file
* file
, const char* path
) {
705 // Check if path is set
711 // Strip any leading dots from paths
712 if (pakfire_string_startswith(path
, "./"))
716 // Just store the path if it is absolute
718 r
= pakfire_string_set(file
->path
, path
);
723 // Handle relative paths
725 r
= pakfire_string_format(file
->path
, "/%s", path
);
731 // Set abspath if it isn't set, yet
732 if (!*file
->abspath
) {
733 r
= pakfire_file_set_abspath(file
, file
->path
);
741 ERROR(file
->pakfire
, "Could not set path '%s': %m\n", path
);
745 PAKFIRE_EXPORT
const char* pakfire_file_get_hardlink(struct pakfire_file
* file
) {
746 if (!*file
->hardlink
)
749 return file
->hardlink
;
752 PAKFIRE_EXPORT
void pakfire_file_set_hardlink(struct pakfire_file
* file
, const char* link
) {
753 pakfire_string_set(file
->hardlink
, link
);
756 PAKFIRE_EXPORT
const char* pakfire_file_get_symlink(struct pakfire_file
* file
) {
760 return file
->symlink
;
763 PAKFIRE_EXPORT
void pakfire_file_set_symlink(struct pakfire_file
* file
, const char* link
) {
764 pakfire_string_set(file
->symlink
, link
);
767 PAKFIRE_EXPORT nlink_t
pakfire_file_get_nlink(struct pakfire_file
* file
) {
768 return file
->st
.st_nlink
;
771 PAKFIRE_EXPORT
void pakfire_file_set_nlink(struct pakfire_file
* file
, const nlink_t nlink
) {
772 file
->st
.st_nlink
= nlink
;
775 PAKFIRE_EXPORT ino_t
pakfire_file_get_inode(struct pakfire_file
* file
) {
776 return file
->st
.st_ino
;
779 PAKFIRE_EXPORT
void pakfire_file_set_inode(struct pakfire_file
* file
, const ino_t ino
) {
780 file
->st
.st_ino
= ino
;
783 PAKFIRE_EXPORT dev_t
pakfire_file_get_dev(struct pakfire_file
* file
) {
784 return file
->st
.st_dev
;
787 PAKFIRE_EXPORT
void pakfire_file_set_dev(struct pakfire_file
* file
, const dev_t dev
) {
788 file
->st
.st_dev
= dev
;
791 PAKFIRE_EXPORT
int pakfire_file_get_type(struct pakfire_file
* file
) {
792 return file
->st
.st_mode
& S_IFMT
;
795 PAKFIRE_EXPORT off_t
pakfire_file_get_size(struct pakfire_file
* file
) {
796 return file
->st
.st_size
;
799 PAKFIRE_EXPORT
void pakfire_file_set_size(struct pakfire_file
* file
, off_t size
) {
800 file
->st
.st_size
= size
;
803 PAKFIRE_EXPORT
const char* pakfire_file_get_uname(struct pakfire_file
* file
) {
807 PAKFIRE_EXPORT
int pakfire_file_set_uname(struct pakfire_file
* file
, const char* uname
) {
808 return pakfire_string_set(file
->uname
, uname
);
811 PAKFIRE_EXPORT
const char* pakfire_file_get_gname(struct pakfire_file
* file
) {
815 PAKFIRE_EXPORT
int pakfire_file_set_gname(struct pakfire_file
* file
, const char* gname
) {
816 return pakfire_string_set(file
->gname
, gname
);
819 PAKFIRE_EXPORT mode_t
pakfire_file_get_mode(struct pakfire_file
* file
) {
820 return file
->st
.st_mode
;
823 PAKFIRE_EXPORT
void pakfire_file_set_mode(struct pakfire_file
* file
, mode_t mode
) {
824 file
->st
.st_mode
= mode
;
827 PAKFIRE_EXPORT mode_t
pakfire_file_get_perms(struct pakfire_file
* file
) {
828 return file
->st
.st_mode
& ~S_IFMT
;
831 PAKFIRE_EXPORT
void pakfire_file_set_perms(struct pakfire_file
* file
, const mode_t perms
) {
832 // Clear any previous permissions
833 file
->st
.st_mode
&= S_IFMT
;
835 // Set new bits (with format cleared)
836 file
->st
.st_mode
|= ~S_IFMT
& perms
;
839 PAKFIRE_EXPORT
time_t pakfire_file_get_ctime(struct pakfire_file
* file
) {
840 return file
->st
.st_ctime
;
843 PAKFIRE_EXPORT
void pakfire_file_set_ctime(struct pakfire_file
* file
, time_t time
) {
844 file
->st
.st_ctime
= time
;
847 PAKFIRE_EXPORT
time_t pakfire_file_get_mtime(struct pakfire_file
* file
) {
848 return file
->st
.st_mtime
;
851 PAKFIRE_EXPORT
void pakfire_file_set_mtime(struct pakfire_file
* file
, time_t time
) {
852 file
->st
.st_mtime
= time
;
855 PAKFIRE_EXPORT
const unsigned char* pakfire_file_get_digest(
856 struct pakfire_file
* file
, const enum pakfire_digest_types type
, size_t* length
) {
859 case PAKFIRE_DIGEST_SHA3_512
:
860 if (!pakfire_digest_set(file
->digests
.sha3_512
))
864 *length
= sizeof(file
->digests
.sha3_512
);
866 return file
->digests
.sha3_512
;
868 case PAKFIRE_DIGEST_SHA3_256
:
869 if (!pakfire_digest_set(file
->digests
.sha3_256
))
873 *length
= sizeof(file
->digests
.sha3_256
);
875 return file
->digests
.sha3_256
;
877 case PAKFIRE_DIGEST_BLAKE2B512
:
878 if (!pakfire_digest_set(file
->digests
.blake2b512
))
882 *length
= sizeof(file
->digests
.blake2b512
);
884 return file
->digests
.blake2b512
;
886 case PAKFIRE_DIGEST_BLAKE2S256
:
887 if (!pakfire_digest_set(file
->digests
.blake2s256
))
891 *length
= sizeof(file
->digests
.blake2s256
);
893 return file
->digests
.blake2s256
;
895 case PAKFIRE_DIGEST_SHA2_512
:
896 if (!pakfire_digest_set(file
->digests
.sha2_512
))
900 *length
= sizeof(file
->digests
.sha2_512
);
902 return file
->digests
.sha2_512
;
904 case PAKFIRE_DIGEST_SHA2_256
:
905 if (!pakfire_digest_set(file
->digests
.sha2_256
))
909 *length
= sizeof(file
->digests
.sha2_256
);
911 return file
->digests
.sha2_256
;
913 case PAKFIRE_DIGEST_UNDEFINED
:
920 PAKFIRE_EXPORT
int pakfire_file_set_digest(struct pakfire_file
* file
,
921 const enum pakfire_digest_types type
, const unsigned char* digest
, const size_t length
) {
927 // Check buffer length
928 if (pakfire_digest_length(type
) != length
) {
929 ERROR(file
->pakfire
, "Digest has an incorrect length of %zu byte(s)\n", length
);
936 case PAKFIRE_DIGEST_SHA3_512
:
937 memcpy(file
->digests
.sha3_512
, digest
, sizeof(file
->digests
.sha3_512
));
940 case PAKFIRE_DIGEST_SHA3_256
:
941 memcpy(file
->digests
.sha3_256
, digest
, sizeof(file
->digests
.sha3_256
));
944 case PAKFIRE_DIGEST_BLAKE2B512
:
945 memcpy(file
->digests
.blake2b512
, digest
, sizeof(file
->digests
.blake2b512
));
948 case PAKFIRE_DIGEST_BLAKE2S256
:
949 memcpy(file
->digests
.blake2s256
, digest
, sizeof(file
->digests
.blake2s256
));
952 case PAKFIRE_DIGEST_SHA2_512
:
953 memcpy(file
->digests
.sha2_512
, digest
, sizeof(file
->digests
.sha2_512
));
956 case PAKFIRE_DIGEST_SHA2_256
:
957 memcpy(file
->digests
.sha2_256
, digest
, sizeof(file
->digests
.sha2_256
));
960 case PAKFIRE_DIGEST_UNDEFINED
:
968 static int pakfire_file_levels(struct pakfire_file
* file
) {
974 for (char* p
= file
->path
; *p
; p
++) {
982 FILE* pakfire_file_open(struct pakfire_file
* file
) {
983 FILE* f
= fopen(file
->abspath
, "r");
985 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
990 static int __pakfire_file_compute_digests(struct pakfire_file
* file
,
991 struct pakfire_digests
* digests
, const int types
) {
995 // Skip this for anything that isn't a regular file
996 if (!S_ISREG(file
->st
.st_mode
))
1000 pakfire_digests_reset(digests
, types
);
1003 f
= pakfire_file_open(file
);
1008 r
= pakfire_digests_compute_from_file(file
->pakfire
, digests
, types
, f
);
1019 int pakfire_file_compute_digests(struct pakfire_file
* file
, const int types
) {
1020 return __pakfire_file_compute_digests(file
, &file
->digests
, types
);
1023 int pakfire_file_remove(struct pakfire_file
* file
) {
1024 if (!*file
->abspath
) {
1029 DEBUG(file
->pakfire
, "Removing %s...\n", file
->path
);
1031 int r
= remove(file
->abspath
);
1034 // Ignore when we could not remove directories
1038 // Ignore if the file didn't exist
1046 ERROR(file
->pakfire
, "Could not remove %s (%s): %m\n", file
->path
, file
->abspath
);
1052 int pakfire_file_symlink_target_exists(struct pakfire_file
* file
) {
1053 // Fail if this got called for anything that isn't a symlink
1054 if (!S_ISLNK(file
->st
.st_mode
)) {
1059 return pakfire_path_exists(file
->abspath
);
1066 int pakfire_file_detect_mimetype(struct pakfire_file
* file
) {
1067 // Only process regular files
1068 if (!S_ISREG(file
->st
.st_mode
))
1071 // Skip if MIME type is already set
1072 if (*file
->mimetype
)
1075 // Fetch the magic cookie
1076 magic_t magic
= pakfire_get_magic(file
->pakfire
);
1081 const char* mimetype
= magic_file(magic
, file
->abspath
);
1083 ERROR(file
->pakfire
, "Could not classify %s: %s\n", file
->path
, magic_error(magic
));
1087 DEBUG(file
->pakfire
, "Classified %s as %s\n", file
->path
, mimetype
);
1090 return pakfire_file_set_mimetype(file
, mimetype
);
1093 PAKFIRE_EXPORT
const char* pakfire_file_get_mimetype(struct pakfire_file
* file
) {
1094 // Return nothing on an empty mimetype
1095 if (!*file
->mimetype
)
1098 return file
->mimetype
;
1101 PAKFIRE_EXPORT
int pakfire_file_set_mimetype(
1102 struct pakfire_file
* file
, const char* mimetype
) {
1104 return pakfire_string_set(file
->mimetype
, mimetype
);
1111 static int setup_libelf(struct pakfire
* pakfire
) {
1112 // Initialize libelf
1113 if (elf_version(EV_CURRENT
) == EV_NONE
) {
1114 ERROR(pakfire
, "Could not initialize libelf: %s\n", elf_errmsg(-1));
1122 static int pakfire_file_classify_mode(struct pakfire_file
* file
) {
1123 // Check for regular files
1124 if (S_ISREG(file
->st
.st_mode
)) {
1125 file
->class |= PAKFIRE_FILE_REGULAR
;
1127 // Does the file have executable permissions?
1128 if (file
->st
.st_mode
& (S_IXUSR
|S_IXGRP
|S_IXOTH
))
1129 file
->class |= PAKFIRE_FILE_EXECUTABLE
;
1131 // Check for directories
1132 } else if (S_ISDIR(file
->st
.st_mode
))
1133 file
->class |= PAKFIRE_FILE_DIRECTORY
;
1135 // Check for symlinks
1136 else if (S_ISLNK(file
->st
.st_mode
))
1137 file
->class |= PAKFIRE_FILE_SYMLINK
;
1139 // Check for character devices
1140 else if (S_ISCHR(file
->st
.st_mode
))
1141 file
->class |= PAKFIRE_FILE_CHARACTER
;
1143 // Check for block devices
1144 else if (S_ISBLK(file
->st
.st_mode
))
1145 file
->class |= PAKFIRE_FILE_BLOCK
;
1147 // Check for FIFO pipes
1148 else if (S_ISFIFO(file
->st
.st_mode
))
1149 file
->class |= PAKFIRE_FILE_FIFO
;
1151 // Check for sockets
1152 else if (S_ISSOCK(file
->st
.st_mode
))
1153 file
->class |= PAKFIRE_FILE_SOCKET
;
1158 static const struct pattern
{
1159 const char* pattern
;
1162 { "*.a", PAKFIRE_FILE_STATIC_LIBRARY
},
1163 { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE
},
1164 { "*.pm", PAKFIRE_FILE_PERL
},
1165 { "*.pc", PAKFIRE_FILE_PKGCONFIG
},
1166 { "/usr/lib/firmware/*", PAKFIRE_FILE_FIRMWARE
},
1167 { "/usr/lib*/ld-*.so*", PAKFIRE_FILE_RUNTIME_LINKER
},
1171 static int pakfire_file_classify_pattern(struct pakfire_file
* file
) {
1172 for (const struct pattern
* p
= patterns
; p
->pattern
; p
++) {
1173 if (pakfire_file_matches(file
, p
->pattern
)) {
1174 file
->class |= p
->class;
1182 static const struct mimetype
{
1183 const char* mimetype
;
1186 { "text/x-perl", PAKFIRE_FILE_PERL
},
1190 static int pakfire_file_classify_magic(struct pakfire_file
* file
) {
1193 // Detect the MIME type
1194 r
= pakfire_file_detect_mimetype(file
);
1198 // Fetch the MIME type
1199 const char* mimetype
= pakfire_file_get_mimetype(file
);
1203 // Match the MIME type with a flag
1204 for (const struct mimetype
* m
= mimetypes
; m
->mimetype
; m
++) {
1205 if (strcmp(m
->mimetype
, mimetype
) == 0) {
1206 file
->class |= m
->class;
1214 static int pakfire_file_classify_elf(struct pakfire_file
* file
) {
1219 // Don't run this if we already know that file is an ELF file
1220 if (file
->class & PAKFIRE_FILE_ELF
)
1224 r
= setup_libelf(file
->pakfire
);
1229 f
= fopen(file
->abspath
, "r");
1231 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->path
);
1235 // Try to open the ELF file
1236 elf
= elf_begin(fileno(f
), ELF_C_READ
, NULL
);
1238 // We fail silently here, because this file might be in a different format
1242 switch (elf_kind(elf
)) {
1243 // Mark this file as an ELF file
1245 file
->class |= PAKFIRE_FILE_ELF
;
1248 // Ignore everything else
1262 int pakfire_file_classify(struct pakfire_file
* file
) {
1266 // First, check the mode so that we won't run magic on directories, symlinks, ...
1267 r
= pakfire_file_classify_mode(file
);
1271 // Only run this for regular files
1272 if (file
->class & PAKFIRE_FILE_REGULAR
) {
1273 // Then check for patterns
1274 r
= pakfire_file_classify_pattern(file
);
1278 // After that, we will use libmagic...
1279 r
= pakfire_file_classify_magic(file
);
1283 // Check if the file is an ELF file
1284 r
= pakfire_file_classify_elf(file
);
1294 file
->class = PAKFIRE_FILE_UNKNOWN
;
1299 int pakfire_file_matches_class(struct pakfire_file
* file
, const int class) {
1300 return pakfire_file_classify(file
) & class;
1304 This function tries to remove the file after it has been packaged.
1306 It will try to delete any parent directories as well and ignore if directories
1307 cannot be deleted because they might contain other files
1309 int pakfire_file_cleanup(struct pakfire_file
* file
) {
1310 char path
[PATH_MAX
];
1312 // Try removing the file
1313 int r
= pakfire_file_remove(file
);
1317 // Create a working copy of abspath
1318 r
= pakfire_string_set(path
, file
->abspath
);
1322 // See how many levels this file has
1323 int levels
= pakfire_file_levels(file
);
1325 // Walk all the way up and remove all parent directories if possible
1329 // Break if path is suddenly empty
1333 DEBUG(file
->pakfire
, "Trying to remove parent directory %s\n", path
);
1337 // Break on any error
1345 static int pakfire_file_verify_mode(struct pakfire_file
* file
, const struct stat
* st
) {
1346 const mode_t type
= pakfire_file_get_type(file
);
1348 // Did the type change?
1349 if (type
!= (st
->st_mode
& S_IFMT
)) {
1350 file
->verify_status
|= PAKFIRE_FILE_TYPE_CHANGED
;
1352 DEBUG(file
->pakfire
, "%s: File Type changed\n", file
->path
);
1355 const mode_t perms
= pakfire_file_get_perms(file
);
1357 // Check permissions
1358 if (perms
!= (st
->st_mode
& 0777)) {
1359 file
->verify_status
|= PAKFIRE_FILE_PERMISSIONS_CHANGED
;
1361 DEBUG(file
->pakfire
, "%s: Permissions changed\n", file
->path
);
1365 // XXX This does not check what it is supposed to check
1367 // Check if device node changed
1368 if (S_ISCHR(st
->st_mode
) || S_ISBLK(st
->st_mode
)) {
1369 const dev_t dev
= pakfire_file_get_dev(file
);
1371 if (dev
!= st
->st_dev
) {
1372 file
->verify_status
|= PAKFIRE_FILE_DEV_CHANGED
;
1374 DEBUG(file
->pakfire
, "%s: Device Node changed\n", file
->path
);
1382 static int pakfire_file_verify_size(struct pakfire_file
* file
, const struct stat
* st
) {
1383 // Nothing to do if size matches
1384 if (file
->st
.st_size
== st
->st_size
)
1388 file
->verify_status
|= PAKFIRE_FILE_SIZE_CHANGED
;
1390 DEBUG(file
->pakfire
, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
1391 file
->path
, file
->st
.st_size
, st
->st_size
);
1396 static int pakfire_file_verify_ownership(struct pakfire_file
* file
, const struct stat
* st
) {
1399 const uid_t uid
= pakfire_unmap_id(file
->pakfire
, st
->st_uid
);
1400 const gid_t gid
= pakfire_unmap_id(file
->pakfire
, st
->st_gid
);
1402 const uid_t uid
= st
->st_uid
;
1403 const gid_t gid
= st
->st_gid
;
1406 // Fetch owner & group
1407 struct passwd
* owner
= pakfire_getpwnam(file
->pakfire
, file
->uname
);
1408 struct group
* group
= pakfire_getgrnam(file
->pakfire
, file
->gname
);
1410 // Check if owner matches
1411 if (!owner
|| owner
->pw_uid
!= uid
) {
1412 file
->verify_status
|= PAKFIRE_FILE_OWNER_CHANGED
;
1414 DEBUG(file
->pakfire
, "%s: Owner differs\n", file
->path
);
1417 // Check if group matches
1418 if (!group
|| group
->gr_gid
!= gid
) {
1419 file
->verify_status
|= PAKFIRE_FILE_GROUP_CHANGED
;
1421 DEBUG(file
->pakfire
, "%s: Group differs\n", file
->path
);
1427 static int pakfire_file_verify_timestamps(struct pakfire_file
* file
, const struct stat
* st
) {
1428 // Check creation time
1429 if (file
->st
.st_ctime
!= st
->st_ctime
) {
1430 file
->verify_status
|= PAKFIRE_FILE_CTIME_CHANGED
;
1432 DEBUG(file
->pakfire
, "%s: Creation time changed\n", file
->path
);
1435 // Check modification time
1436 if (file
->st
.st_mtime
!= st
->st_mtime
) {
1437 file
->verify_status
|= PAKFIRE_FILE_MTIME_CHANGED
;
1439 DEBUG(file
->pakfire
, "%s: Modification time changed\n", file
->path
);
1445 static int pakfire_file_verify_payload(struct pakfire_file
* file
, const struct stat
* st
) {
1448 struct pakfire_digests computed_digests
;
1449 int digest_types
= PAKFIRE_DIGEST_UNDEFINED
;
1451 // Nothing to do for anything that isn't a regular file
1452 if (!S_ISREG(st
->st_mode
))
1455 // Fast-path if size changed. The payload will have changed, too
1456 if (file
->verify_status
& PAKFIRE_FILE_SIZE_CHANGED
) {
1457 file
->verify_status
|= PAKFIRE_FILE_PAYLOAD_CHANGED
;
1461 // Check if this file has any digests at all
1462 digest_types
= pakfire_digest_has_any(&file
->digests
);
1464 if (!digest_types
) {
1465 ERROR(file
->pakfire
, "%s: No digests available\n", file
->path
);
1470 r
= __pakfire_file_compute_digests(file
, &computed_digests
, digest_types
);
1475 r
= pakfire_digests_compare(file
->pakfire
, &file
->digests
, &computed_digests
, digest_types
);
1477 file
->verify_status
|= PAKFIRE_FILE_PAYLOAD_CHANGED
;
1479 DEBUG(file
->pakfire
, "%s: Digest(s) do not match\n", file
->path
);
1487 Verify the file - i.e. does the metadata match what is on disk?
1489 int pakfire_file_verify(struct pakfire_file
* file
, int* status
) {
1493 DEBUG(file
->pakfire
, "Verifying %s...\n", file
->path
);
1496 r
= lstat(file
->abspath
, &st
);
1498 // File does not exist
1499 if (errno
== ENOENT
) {
1500 file
->verify_status
|= PAKFIRE_FILE_NOENT
;
1504 // Raise any other errors from stat()
1509 r
= pakfire_file_verify_mode(file
, &st
);
1514 r
= pakfire_file_verify_size(file
, &st
);
1519 r
= pakfire_file_verify_ownership(file
, &st
);
1523 // Verify timestamps
1524 r
= pakfire_file_verify_timestamps(file
, &st
);
1529 r
= pakfire_file_verify_payload(file
, &st
);
1536 PAKFIRE_EXPORT
int pakfire_file_matches(struct pakfire_file
* file
, const char* pattern
) {
1539 // Don't match on no pattern
1543 // Check if the pattern matches
1544 r
= fnmatch(pattern
, file
->path
, 0);
1563 static int pakfire_file_open_elf(struct pakfire_file
* file
,
1564 int (*callback
)(struct pakfire_file
* file
, Elf
* elf
, void* data
), void* data
) {
1569 // Don't run this for non-ELF files
1570 if (!pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
1576 r
= setup_libelf(file
->pakfire
);
1581 f
= fopen(file
->abspath
, "r");
1583 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
1587 // Parse the ELF header
1588 elf
= elf_begin(fileno(f
), ELF_C_READ
, NULL
);
1590 ERROR(file
->pakfire
, "Could not open ELF file: %s\n", elf_errmsg(-1));
1595 // Check if this is an ELF file
1596 switch (elf_kind(elf
)) {
1601 ERROR(file
->pakfire
, "%s is not an ELF object\n", file
->path
);
1606 // Call the callback
1607 r
= callback(file
, elf
, data
);
1618 static int __pakfire_file_get_elf_type(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1619 int* type
= (int*)data
;
1622 // Fetch the ELF header
1623 if (!gelf_getehdr(elf
, &ehdr
)) {
1624 ERROR(file
->pakfire
, "Could not parse ELF header: %s\n", elf_errmsg(-1));
1629 *type
= ehdr
.e_type
;
1634 static int pakfire_file_get_elf_type(struct pakfire_file
* file
) {
1638 r
= pakfire_file_open_elf(file
, __pakfire_file_get_elf_type
, &type
);
1645 static int __pakfire_file_is_stripped(struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1646 Elf_Scn
* section
= NULL
;
1649 // Walk through all sections
1651 section
= elf_nextscn(elf
, section
);
1655 // Fetch the section header
1656 gelf_getshdr(section
, &shdr
);
1658 switch (shdr
.sh_type
) {
1659 // Break if we found the symbol table
1666 DEBUG(file
->pakfire
, "%s has no debug sections\n", file
->path
);
1671 int pakfire_file_is_stripped(struct pakfire_file
* file
) {
1672 // Don't run this for non-ELF files
1673 if (!pakfire_file_matches_class(file
, PAKFIRE_FILE_ELF
)) {
1678 // Do not perform this check on firmware
1679 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_FIRMWARE
))
1682 switch (pakfire_file_get_elf_type(file
)) {
1683 // Do not check Relocatable Objects
1687 // Check everything else
1692 return pakfire_file_open_elf(file
, __pakfire_file_is_stripped
, NULL
);
1695 static int __pakfire_file_hardening_check_ssp(
1696 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1697 Elf_Scn
* section
= NULL
;
1698 GElf_Shdr section_header
;
1699 Elf_Data
* elf_data
= NULL
;
1701 const char* name
= NULL
;
1703 // Count any global functions
1706 // Walk through all sections
1708 section
= elf_nextscn(elf
, section
);
1710 ERROR(file
->pakfire
, "%s has no symbol table\n", file
->path
);
1714 // Fetch the section header
1715 gelf_getshdr(section
, §ion_header
);
1717 // Break if we found the symbol table
1718 if (section_header
.sh_type
== SHT_SYMTAB
)
1722 // Fetch a pointer to the section data
1723 elf_data
= elf_getdata(section
, NULL
);
1725 // Walk through all symbols
1726 for (unsigned int i
= 0; i
< section_header
.sh_size
/ section_header
.sh_entsize
; i
++) {
1727 gelf_getsym(elf_data
, i
, &symbol
);
1729 // Fetch the symbol name
1730 name
= elf_strptr(elf
, section_header
.sh_link
, symbol
.st_name
);
1732 // Skip empty section names
1733 if (!name
|| !*name
)
1736 // Exit if there is a symbol called "__stack_chk_fail"
1737 if (pakfire_string_startswith(name
, "__stack_chk_fail"))
1740 // Count any global functions
1741 if ((ELF64_ST_BIND(symbol
.st_info
) == STB_GLOBAL
) &&
1742 (ELF64_ST_TYPE(symbol
.st_info
) == STT_FUNC
))
1746 // We do not perform the check for libraries that do not contain any functions.
1747 // Some packages use shared libraries to provide data.
1749 DEBUG(file
->pakfire
, "%s: File has no functions. Skipping SSP check.\n", file
->path
);
1753 // The file does not seem to have SSP enabled
1754 file
->hardening_issues
|= PAKFIRE_FILE_NO_SSP
;
1759 static int pakfire_file_hardening_check_ssp(struct pakfire_file
* file
) {
1760 // Do not perform this check for runtime linkers
1761 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_RUNTIME_LINKER
))
1764 return pakfire_file_open_elf(file
, __pakfire_file_hardening_check_ssp
, NULL
);
1767 static int pakfire_file_hardening_check_pie(struct pakfire_file
* file
) {
1768 switch (pakfire_file_get_elf_type(file
)) {
1769 // Shared Object files are good
1773 // Everything else is bad
1775 file
->hardening_issues
|= PAKFIRE_FILE_NO_PIE
;
1782 static int __pakfire_file_hardening_check_execstack(
1783 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1789 // Fetch the total numbers of program headers
1790 r
= elf_getphdrnum(elf
, &phnum
);
1792 ERROR(file
->pakfire
, "Could not fetch number of program headers: %s\n",
1797 // Walk through all program headers
1798 for (unsigned int i
= 0; i
< phnum
; i
++) {
1799 if (!gelf_getphdr(elf
, i
, &phdr
)) {
1800 ERROR(file
->pakfire
, "Could not parse program header: %s\n", elf_errmsg(-1));
1804 switch (phdr
.p_type
) {
1806 DEBUG(file
->pakfire
,
1807 "%s: GNU_STACK flags: %c%c%c\n",
1809 (phdr
.p_flags
& PF_R
) ? 'R' : '-',
1810 (phdr
.p_flags
& PF_W
) ? 'W' : '-',
1811 (phdr
.p_flags
& PF_X
) ? 'X' : '-'
1814 // The stack cannot be writable and executable
1815 if ((phdr
.p_flags
& PF_W
) && (phdr
.p_flags
& PF_X
))
1816 file
->hardening_issues
|= PAKFIRE_FILE_EXECSTACK
;
1829 static int pakfire_file_hardening_check_execstack(struct pakfire_file
* file
) {
1830 return pakfire_file_open_elf(file
, __pakfire_file_hardening_check_execstack
, NULL
);
1833 static int __pakfire_file_hardening_check_partially_relro(
1834 struct pakfire_file
* file
, Elf
* elf
, void* data
) {
1840 // Fetch the total numbers of program headers
1841 r
= elf_getphdrnum(elf
, &phnum
);
1843 ERROR(file
->pakfire
, "Could not fetch number of program headers: %s\n",
1848 // Walk through all program headers
1849 for (unsigned int i
= 0; i
< phnum
; i
++) {
1850 if (!gelf_getphdr(elf
, i
, &phdr
)) {
1851 ERROR(file
->pakfire
, "Could not parse program header: %s\n", elf_errmsg(-1));
1855 switch (phdr
.p_type
) {
1864 // This file does not seem to have PT_GNU_RELRO set
1865 file
->hardening_issues
|= PAKFIRE_FILE_NO_PARTIALLY_RELRO
;
1870 static int pakfire_file_hardening_check_relro(struct pakfire_file
* file
) {
1871 return pakfire_file_open_elf(file
, __pakfire_file_hardening_check_partially_relro
, NULL
);
1875 int pakfire_file_check_hardening(struct pakfire_file
* file
, int* issues
) {
1878 // Do not perform this check on firmware
1879 if (pakfire_file_matches_class(file
, PAKFIRE_FILE_FIRMWARE
))
1882 // Return previous result if this has been run before
1883 if (!file
->hardening_check_done
) {
1884 switch (pakfire_file_get_elf_type(file
)) {
1885 // Do not check Relocatable Objects
1889 // Check everything else
1895 r
= pakfire_file_hardening_check_ssp(file
);
1900 r
= pakfire_file_hardening_check_pie(file
);
1904 // Check for executable stacks
1905 r
= pakfire_file_hardening_check_execstack(file
);
1910 r
= pakfire_file_hardening_check_relro(file
);
1916 file
->hardening_check_done
= 1;
1919 // Return any issues
1921 *issues
= file
->hardening_issues
;