38{
39 const int rawFd = ::open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
40 if (rawFd < 0)
42 const UniqueFd fd(rawFd);
43
44 struct stat status {};
45 if (::fstat(fd.get(), &status) != 0)
47
48 if (!S_ISREG(status.st_mode))
49 throw std::runtime_error("la policy deve essere un file regolare");
50 if (status.st_size < 0 ||
51 static_cast<std::uintmax_t>(status.st_size) > kMaximumPolicyBytes) {
52 throw std::runtime_error("la policy supera il limite di 1 MiB");
53 }
54
55 if (requireSecureOwnership) {
56 if (status.st_uid != 0)
57 throw std::runtime_error("la policy deve appartenere a root");
59 throw std::runtime_error(
60 "la policy non deve essere scrivibile da gruppo o altri");
61 }
62 }
63
64 std::string content;
65 content.reserve(static_cast<std::size_t>(status.st_size));
66 char buffer[4096];
67 for (;;) {
68 const ssize_t count =
::read(fd.get(), buffer,
sizeof(buffer));
69 if (count == 0)
70 break;
71 if (count < 0) {
72 if (errno == EINTR)
73 continue;
75 }
76 if (content.size() + static_cast<std::size_t>(count) >
77 kMaximumPolicyBytes) {
78 throw std::runtime_error("la policy supera il limite di 1 MiB");
79 }
80 content.append(buffer, static_cast<std::size_t>(count));
81 }
82
83 struct stat finalStatus {};
84 if (::fstat(fd.get(), &finalStatus) != 0)
86 if (finalStatus.st_dev != status.st_dev ||
87 finalStatus.st_ino != status.st_ino ||
88 finalStatus.st_size != status.st_size ||
89 finalStatus.st_mtim.tv_sec != status.st_mtim.tv_sec ||
90 finalStatus.st_mtim.tv_nsec != status.st_mtim.tv_nsec ||
91 finalStatus.st_ctim.tv_sec != status.st_ctim.tv_sec ||
92 finalStatus.st_ctim.tv_nsec != status.st_ctim.tv_nsec) {
93 throw std::runtime_error("la policy è cambiata durante la lettura");
94 }
95
96 return content;
97}
static std::string read(const std::filesystem::path &path, bool requireSecureOwnership)
std::runtime_error systemError(const char *operation)