zapret/nfq/sec.c
2021-03-05 20:08:49 +03:00

172 lines
2.9 KiB
C

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include "sec.h"
#include <unistd.h>
#include <fcntl.h>
#include <grp.h>
#ifdef __linux__
#include <sys/prctl.h>
bool checkpcap(uint64_t caps)
{
if (!caps) return true; // no special caps reqd
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2];
uint32_t c0 = (uint32_t)caps;
uint32_t c1 = (uint32_t)(caps>>32);
return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1;
}
bool setpcap(uint64_t caps)
{
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2];
cd[0].effective = cd[0].permitted = (uint32_t)caps;
cd[0].inheritable = 0;
cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32);
cd[1].inheritable = 0;
return !capset(&ch,cd);
}
int getmaxcap()
{
int maxcap = CAP_LAST_CAP;
FILE *F = fopen("/proc/sys/kernel/cap_last_cap", "r");
if (F)
{
int n = fscanf(F, "%d", &maxcap);
fclose(F);
}
return maxcap;
}
bool dropcaps()
{
uint64_t caps = (1<<CAP_NET_ADMIN)|(1<<CAP_NET_RAW);
int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
if (prctl(PR_CAPBSET_DROP, cap)<0)
{
fprintf(stderr, "could not drop bound cap %d\n", cap);
perror("cap_drop_bound");
}
}
}
// now without CAP_SETPCAP
if (!setpcap(caps))
{
perror("setpcap");
return checkpcap(caps);
}
return true;
}
#endif
bool can_drop_root()
{
#ifdef __linux__
// has some caps
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
#else
// effective root
return !geteuid();
#endif
}
bool droproot(uid_t uid, gid_t gid)
{
#ifdef __linux__
if (prctl(PR_SET_KEEPCAPS, 1L))
{
perror("prctl(PR_SET_KEEPCAPS)");
return false;
}
#endif
// drop all SGIDs
if (setgroups(0,NULL))
{
perror("setgroups");
return false;
}
if (setgid(gid))
{
perror("setgid");
return false;
}
if (setuid(uid))
{
perror("setuid");
return false;
}
#ifdef __linux__
return dropcaps();
#else
return true;
#endif
}
void print_id()
{
int i,N;
gid_t g[128];
printf("Running as UID=%u GID=",getuid());
N=getgroups(sizeof(g)/sizeof(*g),g);
if (N>0)
{
for(i=0;i<N;i++)
printf(i==(N-1) ? "%u" : "%u,", g[i]);
printf("\n");
}
else
printf("%u\n",getgid());
}
void daemonize()
{
int pid;
pid = fork();
if (pid == -1)
{
perror("fork");
exit(2);
}
else if (pid != 0)
exit(0);
if (setsid() == -1)
exit(2);
if (chdir("/") == -1)
exit(2);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* redirect fd's 0,1,2 to /dev/null */
open("/dev/null", O_RDWR);
int fd;
/* stdin */
fd = dup(0);
/* stdout */
fd = dup(0);
/* stderror */
}
bool writepid(const char *filename)
{
FILE *F;
if (!(F = fopen(filename, "w")))
return false;
fprintf(F, "%d", getpid());
fclose(F);
return true;
}