#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/xattr.h> #include <fcntl.h> #include <time.h> #include <unistd.h> #include <openssl/sha.h> #include <errno.h> #include <limits.h> #include <stdint.h> #include "libhash.h" #define BLOCKSIZE 4096 #define XATTR_SHA512HASH "trusted.sha512.control.lth.se" struct __attribute__((__packed__)) hash_attr { time_t hash_time; time_t mtime; uint32_t mtime_nsec; uint8_t hash[SHA512_DIGEST_LENGTH]; }; int hash_sha512_buf(char *buf, size_t length, unsigned char *hash) { SHA512_CTX ctx; SHA512_Init(&ctx); SHA512_Update(&ctx, buf, length); SHA512_Final(hash, &ctx); return 0; } int hash_sha512_file(char *filename, time_t mtime, int64_t mtime_nsec, int flags, time_t maxage, unsigned char *hash) { int fd; int result = 0, recalc = 1; struct hash_attr hash_attr; if (flags & FLAGS_CLEAR_XATTR) { if (removexattr(filename, XATTR_SHA512HASH) != 0) { if (errno != ENODATA) { result = -1; fprintf(stderr, "Failed to remove xattr '%s'\n", filename); goto out; } else if ((flags & FLAGS_VERBOSE_MASK) > FLAGS_VERBOSE2) { fprintf(stderr, "No xattr for '%s'\n", filename); } } else { if ((flags & FLAGS_VERBOSE_MASK) > FLAGS_VERBOSE2) { fprintf(stderr, "Removed xattr for '%s'\n", filename); } } } if (flags & FLAGS_NO_CALC_HASH) { // We should not calculate hash goto out; } if (flags & FLAGS_READ_XATTR) { int err; err = getxattr(filename, XATTR_SHA512HASH, &hash_attr, sizeof(hash_attr)); if (err < 0 && errno != ENODATA) { result = -1; goto out; } if (err != sizeof(hash_attr)) { recalc = 1; } else if (le64toh(hash_attr.mtime) != mtime) { recalc = 1; } else if (le32toh(hash_attr.mtime_nsec) != mtime_nsec) { recalc = 1; } else if (flags & FLAGS_MAX_AGE && le64toh(hash_attr.hash_time) < maxage) { recalc = 1; } else { recalc = 0; memcpy(hash, hash_attr.hash, SHA512_DIGEST_LENGTH); } } if (recalc == 0) { goto out; } fd = open (filename, O_RDONLY); if (fd < 0) { result = -1; goto out; } else { SHA512_CTX ctx; unsigned char buffer[BLOCKSIZE]; int count; time_t now; time(&now); SHA512_Init(&ctx); while ((count = read(fd, buffer, BLOCKSIZE)) > 0) { SHA512_Update(&ctx, buffer, count); } SHA512_Final(hash, &ctx); if (count < 0) { result = -1; fremovexattr(fd, XATTR_SHA512HASH); goto out_close; } if (flags & FLAGS_WRITE_XATTR) { int err; hash_attr.hash_time = htole64(now); hash_attr.mtime = htole64(mtime); hash_attr.mtime_nsec = htole32(mtime_nsec); memcpy(hash_attr.hash, hash, SHA512_DIGEST_LENGTH); err = fsetxattr(fd, XATTR_SHA512HASH, &hash_attr, sizeof(hash_attr), 0); if (err < 0) { result = -1; fremovexattr(fd, XATTR_SHA512HASH); goto out_close; } } else if (flags & FLAGS_READ_XATTR) { fremovexattr(fd, XATTR_SHA512HASH); } } out_close: close(fd); out: return result; }