diff --git a/docs/changes.txt b/docs/changes.txt index 8e4076e..24ff039 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -494,5 +494,6 @@ nfqws: --synack-split tpws: ipcache of host names nfqws,tpws: set 1024 repeat limit to fakes and dups nfqws,tpws: do more before daemonize +nfqws,tpws: accept multiple gids in --gid init.d: remove --ipset parameter prohibition init.d, blockcheck: drop time exceeded icmp for nfqws-related connections diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 5e6d9ad..ef0b7bc 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef __CYGWIN__ #include "win.h" @@ -297,7 +298,7 @@ static int nfq_main(void) } sec_harden(); - if (params.droproot && !droproot(params.uid, params.gid) || !dropcaps()) + if (params.droproot && !droproot(params.uid, params.gid, params.gid_count) || !dropcaps()) goto err; print_id(); if (params.droproot && !test_list_files()) @@ -421,7 +422,7 @@ static int dvt_main(void) goto exiterr; - if (params.droproot && !droproot(params.uid, params.gid)) + if (params.droproot && !droproot(params.uid, params.gid, params.gid_count)) goto exiterr; print_id(); if (params.droproot && !test_list_files()) @@ -642,33 +643,6 @@ static int win_main(const char *windivert_filter) -static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) -{ - int v; - char *p; - - if ((p = strchr(s,':'))) *p++=0; - v = atoi(s); - if (v < 0 || v>65535) - { - DLOG_ERR("bad wsize\n"); - return false; - } - *wsize=(uint16_t)v; - if (p && *p) - { - v = atoi(p); - if (v < 0 || v>255) - { - DLOG_ERR("bad wscale\n"); - return false; - } - *wscale = (uint8_t)v; - } - return true; -} - - #if !defined( __OpenBSD__) && !defined(__ANDROID__) static void cleanup_args() @@ -701,6 +675,61 @@ static void exit_clean(int code) exit(code); } + +static bool parse_uid(const char *opt, uid_t *uid, gid_t *gid, int *gid_count, int max_gids) +{ + unsigned int u; + char c, *p, *e; + + *gid_count=0; + if ((e = strchr(optarg,':'))) *e++=0; + if (sscanf(opt,"%u",&u)!=1) return false; + *uid = (uid_t)u; + for (p=e ; p ; ) + { + if ((e = strchr(p,','))) + { + c=*e; + *e=0; + } + if (p) + { + if (sscanf(p,"%u",&u)!=1) return false; + if (*gid_count>=max_gids) return false; + gid[(*gid_count)++] = (gid_t)u; + } + if (e) *e++=c; + p = e; + } + return true; +} + +static bool parse_ws_scale_factor(char *s, uint16_t *wsize, uint8_t *wscale) +{ + int v; + char *p; + + if ((p = strchr(s,':'))) *p++=0; + v = atoi(s); + if (v < 0 || v>65535) + { + DLOG_ERR("bad wsize\n"); + return false; + } + *wsize=(uint16_t)v; + if (p && *p) + { + v = atoi(p); + if (v < 0 || v>255) + { + DLOG_ERR("bad wscale\n"); + return false; + } + *wscale = (uint8_t)v; + } + return true; +} + static bool parse_cutoff(const char *opt, unsigned int *value, char *mode) { *mode = (*opt=='n' || *opt=='d' || *opt=='s') ? *opt++ : 'n'; @@ -1462,7 +1491,7 @@ static void exithelp(void) " --pidfile=\t\t\t\t; write pid to file\n" #ifndef __CYGWIN__ " --user=\t\t\t\t; drop root privs\n" - " --uid=uid[:gid]\t\t\t\t; drop root privs\n" + " --uid=uid[:gid1,gid2,...]\t\t\t; drop root privs\n" #endif #ifdef __linux__ " --bind-fix4\t\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n" @@ -1959,9 +1988,10 @@ int main(int argc, char **argv) LIST_INIT(¶ms.ssid_filter); LIST_INIT(¶ms.nlm_filter); #else - if (can_drop_root()) // are we root ? + if (can_drop_root()) { - params.uid = params.gid = 0x7FFFFFFF; // default uid:gid + params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid + params.gid_count = 1; params.droproot = true; } #endif @@ -2059,26 +2089,45 @@ int main(int argc, char **argv) break; #ifndef __CYGWIN__ case IDX_USER: + { + struct passwd *pwd = getpwnam(optarg); + if (!pwd) { - struct passwd *pwd = getpwnam(optarg); - if (!pwd) - { - DLOG_ERR("non-existent username supplied\n"); - exit_clean(1); - } - params.uid = pwd->pw_uid; - params.gid = pwd->pw_gid; - params.droproot = true; - } - break; - case IDX_UID: - params.gid = 0x7FFFFFFF; // default gid. drop gid=0 - params.droproot = true; - if (sscanf(optarg, "%u:%u", ¶ms.uid, ¶ms.gid)<1) - { - DLOG_ERR("--uid should be : uid[:gid]\n"); + DLOG_ERR("non-existent username supplied\n"); exit_clean(1); } + params.uid = pwd->pw_uid; + params.gid_count=MAX_GIDS; +#ifdef __APPLE__ + // silence warning + if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,¶ms.gid_count)<0) +#else + if (getgrouplist(optarg,pwd->pw_gid,params.gid,¶ms.gid_count)<0) +#endif + { + DLOG_ERR("getgrouplist failed. too much groups ?\n"); + exit_clean(1); + } + if (!params.gid_count) + { + params.gid[0] = pwd->pw_gid; + params.gid_count = 1; + } + params.droproot = true; + break; + } + case IDX_UID: + params.droproot = true; + if (!parse_uid(optarg,¶ms.uid,params.gid,¶ms.gid_count,MAX_GIDS)) + { + DLOG_ERR("--uid should be : uid[:gid,gid,...]\n"); + exit_clean(1); + } + if (!params.gid_count) + { + params.gid[0] = 0x7FFFFFFF; + params.gid_count = 1; + } break; #endif case IDX_WSIZE: diff --git a/nfq/params.h b/nfq/params.h index 793de40..5edf9ef 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -63,6 +63,8 @@ #define FAKE_MAX_TCP 1460 #define FAKE_MAX_UDP 1472 +#define MAX_GIDS 64 + enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; struct fake_tls_mod_cache @@ -191,7 +193,8 @@ struct params_s #else bool droproot; uid_t uid; - gid_t gid; + gid_t gid[MAX_GIDS]; + int gid_count; #endif char pidfile[PATH_MAX]; diff --git a/nfq/sec.c b/nfq/sec.c index 6d1649e..34a428d 100644 --- a/nfq/sec.c +++ b/nfq/sec.c @@ -295,8 +295,13 @@ bool can_drop_root(void) #endif } -bool droproot(uid_t uid, gid_t gid) +bool droproot(uid_t uid, gid_t *gid, int gid_count) { + if (gid_count<1) + { + DLOG_ERR("droproot: no groups specified"); + return false; + } #ifdef __linux__ if (prctl(PR_SET_KEEPCAPS, 1L)) { @@ -305,12 +310,12 @@ bool droproot(uid_t uid, gid_t gid) } #endif // drop all SGIDs - if (setgroups(0,NULL)) + if (setgroups(gid_count,gid)) { DLOG_PERROR("setgroups"); return false; } - if (setgid(gid)) + if (setgid(gid[0])) { DLOG_PERROR("setgid"); return false; diff --git a/nfq/sec.h b/nfq/sec.h index 5038225..cfa7b66 100644 --- a/nfq/sec.h +++ b/nfq/sec.h @@ -84,7 +84,7 @@ bool dropcaps(void); #ifndef __CYGWIN__ bool sec_harden(void); bool can_drop_root(void); -bool droproot(uid_t uid, gid_t gid); +bool droproot(uid_t uid, gid_t *gid, int gid_count); void print_id(void); #endif diff --git a/tpws/params.h b/tpws/params.h index 5034586..fdb6f12 100644 --- a/tpws/params.h +++ b/tpws/params.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #if !defined( __OpenBSD__) && !defined(__ANDROID__) @@ -18,13 +19,15 @@ #define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3 #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 -#define FIX_SEG_DEFAULT_MAX_WAIT 50 +#define FIX_SEG_DEFAULT_MAX_WAIT 50 -#define IPCACHE_LIFETIME 7200 +#define IPCACHE_LIFETIME 7200 + +#define MAX_GIDS 64 enum bindll { unwanted=0, no, prefer, force }; -#define MAX_BINDS 32 +#define MAX_BINDS 32 struct bind_s { char bindaddr[64],bindiface[IF_NAMESIZE]; @@ -33,7 +36,7 @@ struct bind_s int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll; }; -#define MAX_SPLITS 16 +#define MAX_SPLITS 16 enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; @@ -116,8 +119,9 @@ struct params_s bool droproot; bool daemon; uid_t uid; - gid_t gid; - char pidfile[256]; + gid_t gid[MAX_GIDS]; + int gid_count; + char pidfile[PATH_MAX]; int maxconn,resolver_threads,maxfiles,max_orphan_time; int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf; #if defined(__linux__) || defined(__APPLE__) diff --git a/tpws/sec.c b/tpws/sec.c index ca48c59..2adb19d 100644 --- a/tpws/sec.c +++ b/tpws/sec.c @@ -169,25 +169,24 @@ static bool set_seccomp(void) bool sec_harden(void) { + bool bRes = true; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)"); - return false; + bRes = false; } #if ARCH_NR!=0 if (!set_seccomp()) { DLOG_PERROR("seccomp"); if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n"); - return false; + bRes = false; } #endif - return true; + return bRes; } - - bool checkpcap(uint64_t caps) { if (!caps) return true; // no special caps reqd @@ -270,8 +269,13 @@ bool can_drop_root(void) #endif } -bool droproot(uid_t uid, gid_t gid) +bool droproot(uid_t uid, gid_t *gid, int gid_count) { + if (gid_count<1) + { + DLOG_ERR("droproot: no groups specified"); + return false; + } #ifdef __linux__ if (prctl(PR_SET_KEEPCAPS, 1L)) { @@ -280,12 +284,12 @@ bool droproot(uid_t uid, gid_t gid) } #endif // drop all SGIDs - if (setgroups(0,NULL)) + if (setgroups(gid_count,gid)) { DLOG_PERROR("setgroups"); return false; } - if (setgid(gid)) + if (setgid(gid[0])) { DLOG_PERROR("setgid"); return false; diff --git a/tpws/sec.h b/tpws/sec.h index 963d947..8a513fa 100644 --- a/tpws/sec.h +++ b/tpws/sec.h @@ -84,7 +84,7 @@ bool dropcaps(void); bool sec_harden(void); bool can_drop_root(); -bool droproot(uid_t uid, gid_t gid); +bool droproot(uid_t uid, gid_t *gid, int gid_count); void print_id(void); void daemonize(void); bool writepid(const char *filename); diff --git a/tpws/tpws.c b/tpws/tpws.c index 9784530..34795fe 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __ANDROID__ #include "andr/ifaddrs.h" @@ -214,7 +215,7 @@ static void exithelp(void) " --daemon\t\t\t\t; daemonize\n" " --pidfile=\t\t\t; write pid to file\n" " --user=\t\t\t; drop root privs\n" - " --uid=uid[:gid]\t\t\t; drop root privs\n" + " --uid=uid[:gid1,gid2,...]\t\t; drop root privs\n" #if defined(__FreeBSD__) " --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n" #endif @@ -583,6 +584,35 @@ static bool parse_ip_list(char *opt, ipset *pp) return true; } +static bool parse_uid(const char *opt, uid_t *uid, gid_t *gid, int *gid_count, int max_gids) +{ + unsigned int u; + char c, *p, *e; + + *gid_count=0; + if ((e = strchr(optarg,':'))) *e++=0; + if (sscanf(opt,"%u",&u)!=1) return false; + *uid = (uid_t)u; + for (p=e ; p ; ) + { + if ((e = strchr(p,','))) + { + c=*e; + *e=0; + } + if (p) + { + if (sscanf(p,"%u",&u)!=1) return false; + if (*gid_count>=max_gids) return false; + gid[(*gid_count)++] = (gid_t)u; + } + if (e) *e++=c; + p = e; + } + return true; +} + + #if !defined( __OpenBSD__) && !defined(__ANDROID__) // no static to not allow optimizer to inline this func (save stack) void config_from_file(const char *filename) @@ -837,8 +867,9 @@ void parse_params(int argc, char *argv[]) if (can_drop_root()) { - params.uid = params.gid = 0x7FFFFFFF; // default uid:gid - params.droproot = true; + params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid + params.gid_count = 1; + params.droproot = true; } struct desync_profile_list *dpl; @@ -954,18 +985,37 @@ void parse_params(int argc, char *argv[]) exit_clean(1); } params.uid = pwd->pw_uid; - params.gid = pwd->pw_gid; + params.gid_count=MAX_GIDS; +#ifdef __APPLE__ + // silence warning + if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,¶ms.gid_count)<0) +#else + if (getgrouplist(optarg,pwd->pw_gid,params.gid,¶ms.gid_count)<0) +#endif + { + DLOG_ERR("getgrouplist failed. too much groups ?\n"); + exit_clean(1); + } + if (!params.gid_count) + { + params.gid[0] = pwd->pw_gid; + params.gid_count = 1; + } params.droproot = true; break; } case IDX_UID: - params.gid=0x7FFFFFFF; // default git. drop gid=0 params.droproot = true; - if (sscanf(optarg,"%u:%u",¶ms.uid,¶ms.gid)<1) + if (!parse_uid(optarg,¶ms.uid,params.gid,¶ms.gid_count,MAX_GIDS)) { - DLOG_ERR("--uid should be : uid[:gid]\n"); + DLOG_ERR("--uid should be : uid[:gid,gid,...]\n"); exit_clean(1); } + if (!params.gid_count) + { + params.gid[0] = 0x7FFFFFFF; + params.gid_count = 1; + } break; case IDX_MAXCONN: params.maxconn = atoi(optarg); @@ -1273,8 +1323,7 @@ void parse_params(int argc, char *argv[]) } break; case IDX_PIDFILE: - strncpy(params.pidfile,optarg,sizeof(params.pidfile)); - params.pidfile[sizeof(params.pidfile)-1]='\0'; + snprintf(params.pidfile,sizeof(params.pidfile),"%s",optarg); break; case IDX_DEBUG: if (optarg) @@ -2087,7 +2136,7 @@ int main(int argc, char *argv[]) set_ulimit(); sec_harden(); - if (params.droproot && !droproot(params.uid,params.gid)) + if (params.droproot && !droproot(params.uid,params.gid,params.gid_count)) goto exiterr; #ifdef __linux__ if (!dropcaps())