srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/include/wireframe/privileges.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/wireframe/privileges.hpp')
-rw-r--r--include/wireframe/privileges.hpp87
1 files changed, 0 insertions, 87 deletions
diff --git a/include/wireframe/privileges.hpp b/include/wireframe/privileges.hpp
deleted file mode 100644
index 69df725..0000000
--- a/include/wireframe/privileges.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#pragma once
-
-#ifndef _WIN32
-#include <grp.h>
-#include <unistd.h>
-#endif
-
-#include <cerrno>
-#include <cstdlib>
-#include <cstring>
-#include <optional>
-#include <string>
-
-// After pcap_open_live() succeeds, the process has gotten everything
-// CAP_NET_RAW exists for - running the rest of the program (decoding
-// untrusted packet bytes, an interactive TUI/GUI event loop) as root
-// from that point on is unnecessary exposure, and PLAN.md says as much
-// directly: "Drop privileges immediately after opening the capture
-// handle; use CAP_NET_RAW via file capabilities instead of running as
-// root."
-//
-// The recommended path doesn't need this file at all: run
-// `sudo setcap cap_net_raw+ep <binary>` once, then invoke the binary
-// directly, unprivileged, forever after - CAP_NET_RAW alone is enough
-// for pcap_open_live(), no root required at any point. This exists for
-// the case someone still runs the binary via sudo (out of habit, or
-// because setcap isn't available/permitted in some environments): drop
-// straight back to the invoking user immediately, so the rest of the
-// process's lifetime - including any -w output file, which then ends
-// up owned by that user instead of root - runs unprivileged either way.
-namespace wireframe {
-
-// Drops from root to the user who actually invoked the program, via
-// sudo's SUDO_UID/SUDO_GID (which sudo always sets). A no-op if not
-// currently root, or if SUDO_UID isn't set (e.g. a genuine root login,
-// not sudo - there's no "real" user to drop to in that case).
-//
-// setuid() to a nonzero UID also clears the process's Linux capability
-// sets as a kernel-level side effect, so this covers both "running as
-// root via sudo" and "root's own CAP_NET_RAW" the same way, without a
-// separate libcap dependency.
-//
-// Returns an error message on failure. The drop is safety-critical: a
-// failure here should be treated as fatal by the caller, not silently
-// ignored while the process keeps running as root.
-inline std::optional<std::string> drop_privileges_if_root() {
-#ifdef _WIN32
- return std::nullopt; // no POSIX privilege model to drop from
-#else
- if (geteuid() != 0) return std::nullopt; // already unprivileged
-
- const char* sudo_uid = std::getenv("SUDO_UID");
- const char* sudo_gid = std::getenv("SUDO_GID");
- if (sudo_uid == nullptr || sudo_gid == nullptr) {
- return std::nullopt; // no safe target to drop to
- }
-
- uid_t target_uid = static_cast<uid_t>(std::strtoul(sudo_uid, nullptr, 10));
- gid_t target_gid = static_cast<gid_t>(std::strtoul(sudo_gid, nullptr, 10));
-
- // Order matters: groups and GID need root to change, so they must
- // be dropped before UID - once UID is gone, so is the privilege
- // to change the others.
- if (setgroups(1, &target_gid) == -1) {
- return "setgroups failed: " + std::string(std::strerror(errno));
- }
- if (setgid(target_gid) == -1) {
- return "setgid failed: " + std::string(std::strerror(errno));
- }
- if (setuid(target_uid) == -1) {
- return "setuid failed: " + std::string(std::strerror(errno));
- }
-
- // Defense in depth (standard advice from setuid-privilege-drop
- // write-ups): confirm root can't be reclaimed. If the saved-UID
- // was somehow left at 0, this would succeed and silently undo the
- // drop - so a *successful* setuid(0) here means something is
- // wrong, and is treated as the failure case.
- if (setuid(0) != -1) {
- return "failed to permanently drop root (setuid(0) unexpectedly succeeded)";
- }
-
- return std::nullopt;
-#endif
-}
-
-} // namespace wireframe