#include "sys.hpp"
#include "common.hpp"
#include <signal.h>
static volatile int SIG = 0;
static void signal_handler(int) {
++SIG;
}
volatile int* setup_signals() {
struct sigaction sa = {};
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL); // so no wait needed
sa.sa_handler = &signal_handler;
sigaction(SIGINT, &sa, NULL); // no SA_RESTART
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
return &SIG;
}
#ifdef NO_DROP_ROOT
bool su(const char*) {
LOG("WARNING: dropping permissions not supported!");
return true;
}
#else
#include <pwd.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#ifndef DROP_USER
#define DROP_USER "nobody"
#endif
bool su(const char* uname) {
if (!uname || !*uname) {
uname = DROP_USER;
}
if (!getuid() || !geteuid() || !getgid() || !getegid()) {
if (chdir("/") != 0) {
LOG_ERRNO("chdir(/)");
return false;
}
const struct passwd* pw = getpwnam(uname);
if (!pw) {
LOG_ERRNO("cannot drop root priviledges: getpwnam(%s)", uname);
return false;
}
cap_value_t cap_values[] = {CAP_NET_ADMIN};
cap_t caps = cap_get_proc();
if (caps == NULL ||
cap_set_flag(caps, CAP_PERMITTED, 2, cap_values, CAP_SET) != 0 ||
cap_set_proc(caps) != 0 ||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0 ||
cap_free(caps) != 0) {
LOG_ERRNO("CAP_PERMITTED: cannot keep capabilities");
return false;
}
if (setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0 || setgid(0) == 0 || setuid(0) == 0) {
LOG_ERRNO("cannot drop root priviledges: set[gu]id(%s)", uname);
return false;
}
caps = cap_get_proc();
if (caps == NULL ||
cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_values, CAP_SET) != 0 ||
cap_set_proc(caps) != 0 ||
cap_free(caps) != 0) {
LOG_ERRNO("CAP_PERMITTED: cannot restore capabilities");
return false;
}
LOG("running as '%s'", uname);
}
return true;
}
#endif // !NO_DROP_ROOT