changes in task handling

This commit is contained in:
tdv
2025-10-15 12:10:23 +03:00
parent 57c4769eeb
commit 2385252fcc
5 changed files with 345 additions and 260 deletions

View File

@@ -1,108 +1,123 @@
#pragma once
#include <filesystem>
#include <string>
#include <array>
#include <vector>
#include <stdexcept>
#include <cstdio>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <spdlog/spdlog.h>
namespace snoop
{
namespace device_sec
{
// --- helpers ---
static std::string Trim(const std::string &s)
{
auto b = s.find_first_not_of(" \t\r\n");
auto e = s.find_last_not_of(" \t\r\n");
if (b == std::string::npos)
return "";
return s.substr(b, e - b + 1);
}
static std::string Exec(const std::string &cmd)
{
std::array<char, 4096> buf{};
std::string out;
FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
if (!pipe)
throw std::runtime_error("popen failed: " + cmd);
while (fgets(buf.data(), (int)buf.size(), pipe) != nullptr)
out.append(buf.data());
int rc = pclose(pipe);
int exitCode = WIFEXITED(rc) ? WEXITSTATUS(rc) : rc;
if (exitCode != 0)
spdlog::warn("Command '{}' exited with code {}", cmd, exitCode);
return out;
}
// dumps the client key from keyring to a temp file and returns its path
static std::filesystem::path ExtractClientKeyFromKernelKeyring()
{
std::string id = Trim(Exec("keyctl search @s user iot-client-key | tail -n1"));
if (id.empty())
throw std::runtime_error("iot-client-key not found in keyring");
// Create a secure temp file
char tmpl[] = "/run/iot/iot-keyXXXXXX";
int fd = mkstemp(tmpl);
if (fd < 0)
throw std::runtime_error("mkstemp failed for client key");
close(fd);
std::filesystem::path p(tmpl);
// Pipe the key payload into the temp file
std::string cmd = "keyctl pipe " + id + " > " + p.string();
Exec(cmd);
// quick sanity
if (std::filesystem::file_size(p) == 0)
{
std::error_code ec;
std::filesystem::remove(p, ec);
throw std::runtime_error("keyctl pipe produced empty client key");
}
return p;
}
struct TempFile
{
std::filesystem::path path;
int fd{-1};
explicit TempFile(const std::filesystem::path &dir, const char *pattern = "iot-keyXXXXXX")
{
std::string tmpl = (dir / pattern).string();
std::vector<char> name(tmpl.begin(), tmpl.end());
name.push_back('\0');
fd = mkstemp(name.data());
if (fd < 0)
throw std::runtime_error("mkstemp failed");
fchmod(fd, S_IRUSR | S_IWUSR);
path = name.data();
}
void write_all(const void *data, size_t n)
{
const uint8_t *p = static_cast<const uint8_t *>(data);
size_t off = 0;
while (off < n)
{
ssize_t w = ::write(fd, p + off, n - off);
if (w <= 0)
throw std::runtime_error("write failed");
off += (size_t)w;
}
fsync(fd);
}
~TempFile()
{
if (fd >= 0)
::close(fd);
std::error_code ec;
std::filesystem::remove(path, ec);
}
};
}
#pragma once
#include <filesystem>
#include <string>
#include <array>
#include <vector>
#include <stdexcept>
#include <cstdio>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <spdlog/spdlog.h>
namespace snoop
{
namespace device_sec
{
// --- helpers ---
static std::string Trim(const std::string &s)
{
auto b = s.find_first_not_of(" \t\r\n");
auto e = s.find_last_not_of(" \t\r\n");
if (b == std::string::npos)
return "";
return s.substr(b, e - b + 1);
}
static std::string Exec(const std::string &cmd)
{
std::array<char, 4096> buf{};
std::string out;
FILE *pipe = popen((cmd + " 2>&1").c_str(), "r");
if (!pipe)
throw std::runtime_error("popen failed: " + cmd);
while (fgets(buf.data(), (int)buf.size(), pipe) != nullptr)
out.append(buf.data());
int rc = pclose(pipe);
int exitCode = WIFEXITED(rc) ? WEXITSTATUS(rc) : rc;
if (exitCode != 0)
spdlog::warn("Command '{}' exited with code {}", cmd, exitCode);
return out;
}
// dumps the client key from keyring to a temp file and returns its path
static std::filesystem::path ExtractClientKeyFromKernelKeyring()
{
std::string id = Trim(Exec("keyctl search @s user iot-client-key | tail -n1"));
if (id.empty())
throw std::runtime_error("iot-client-key not found in keyring");
// Create a secure temp file
char tmpl[] = "/run/iot/iot-keyXXXXXX";
int fd = mkstemp(tmpl);
if (fd < 0)
throw std::runtime_error("mkstemp failed for client key");
close(fd);
std::filesystem::path p(tmpl);
// Pipe the key payload into the temp file
std::string cmd = "keyctl pipe " + id + " > " + p.string();
Exec(cmd);
// quick sanity
if (std::filesystem::file_size(p) == 0)
{
std::error_code ec;
std::filesystem::remove(p, ec);
throw std::runtime_error("keyctl pipe produced empty client key");
}
return p;
}
struct TempFile
{
std::filesystem::path path;
int fd{-1};
explicit TempFile(const std::filesystem::path &dir, const char *pattern = "iot-keyXXXXXX")
{
std::string tmpl = (dir / pattern).string();
std::vector<char> name(tmpl.begin(), tmpl.end());
name.push_back('\0');
fd = mkstemp(name.data());
if (fd < 0)
throw std::runtime_error("mkstemp failed");
fchmod(fd, S_IRUSR | S_IWUSR);
path = name.data();
}
void write_all(const void *data, size_t n)
{
const uint8_t *p = static_cast<const uint8_t *>(data);
size_t off = 0;
while (off < n)
{
ssize_t w = ::write(fd, p + off, n - off);
if (w <= 0)
throw std::runtime_error("write failed");
off += (size_t)w;
}
fsync(fd);
}
~TempFile()
{
if (fd >= 0)
::close(fd);
std::error_code ec;
std::filesystem::remove(path, ec);
}
};
inline std::vector<uint8_t> ReadClientKeyPayloadFromKeyring()
{
// 1) get key id
std::string id = Trim(Exec("keyctl search @s user iot-client-key | tail -n1"));
if (id.empty())
throw std::runtime_error("iot-client-key not found in keyring");
// 2) capture payload (no redirection to file)
std::string bytes = Exec("keyctl pipe " + id);
if (bytes.empty())
throw std::runtime_error("keyctl pipe returned empty payload");
return std::vector<uint8_t>(bytes.begin(), bytes.end());
}
}
}