From 3fe0e366ed95a81315cb662751dad21ed8cec78f Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 16 Oct 2015 10:11:40 +0200 Subject: [PATCH] When using setuid() also use setgid() and setgroups() Signed-off-by: Nikos Mavrogiannopoulos --- auth.c | 30 ++++++++++++++++---- main.c | 62 ++++++++++++++++++++++++------------------ mainloop.c | 26 ++++++++++++++++-- openconnect-internal.h | 2 ++ 4 files changed, 87 insertions(+), 33 deletions(-) diff --git a/auth.c b/auth.c index 7aee8020..89528bc4 100644 --- a/auth.c +++ b/auth.c @@ -30,6 +30,7 @@ #ifndef _WIN32 #include #include +#include #endif #include @@ -1067,21 +1068,40 @@ static int run_csd_script(struct openconnect_info *vpninfo, char *buf, int bufle if (vpninfo->uid_csd_given && vpninfo->uid_csd != getuid()) { struct passwd *pw; + int e; + + if (setgid(vpninfo->gid_csd)) { + e = errno; + fprintf(stderr, _("Failed to set gid %ld: %s\n"), + (long)vpninfo->uid_csd, strerror(e)); + exit(1); + } + + if (setgroups(1, &vpninfo->gid_csd)) { + e = errno; + fprintf(stderr, _("Failed to set groups to %ld: %s\n"), + (long)vpninfo->uid_csd, strerror(e)); + exit(1); + } if (setuid(vpninfo->uid_csd)) { - fprintf(stderr, _("Failed to set uid %ld\n"), - (long)vpninfo->uid_csd); + e = errno; + fprintf(stderr, _("Failed to set uid %ld: %s\n"), + (long)vpninfo->uid_csd, strerror(e)); exit(1); } + if (!(pw = getpwuid(vpninfo->uid_csd))) { - fprintf(stderr, _("Invalid user uid=%ld\n"), - (long)vpninfo->uid_csd); + e = errno; + fprintf(stderr, _("Invalid user uid=%ld: %s\n"), + (long)vpninfo->uid_csd, strerror(e)); exit(1); } setenv("HOME", pw->pw_dir, 1); if (chdir(pw->pw_dir)) { + e = errno; fprintf(stderr, _("Failed to change to CSD home directory '%s': %s\n"), - pw->pw_dir, strerror(errno)); + pw->pw_dir, strerror(e)); exit(1); } } diff --git a/main.c b/main.c index 9dd295ac..20920e6e 100644 --- a/main.c +++ b/main.c @@ -963,6 +963,37 @@ static int next_option(int argc, char **argv, char **config_arg) } +#ifndef _WIN32 +static void get_uids(const char *config_arg, uid_t *uid, gid_t *gid) +{ + char *strend; + struct passwd *pw; + int e; + + *uid = strtol(config_arg, &strend, 0); + if (strend[0]) { + pw = getpwnam(config_arg); + if (!pw) { + e = errno; + fprintf(stderr, _("Invalid user \"%s\": %s\n"), + config_arg, strerror(e)); + exit(1); + } + *uid = pw->pw_uid; + *gid = pw->pw_gid; + } else { + pw = getpwuid(*uid); + if (!pw) { + e = errno; + fprintf(stderr, _("Invalid user ID \"%d\": %s\n"), + (int)*uid, strerror(e)); + exit(1); + } + *gid = pw->pw_gid; + } +} +#endif + int main(int argc, char **argv) { struct openconnect_info *vpninfo; @@ -1033,6 +1064,7 @@ int main(int argc, char **argv) #else vpninfo->use_tun_script = 0; vpninfo->uid = getuid(); + vpninfo->gid = getgid(); if (!uname(&utsbuf)) { free(vpninfo->localname); vpninfo->localname = xstrdup(utsbuf.nodename); @@ -1055,35 +1087,13 @@ int main(int argc, char **argv) case 'S': vpninfo->use_tun_script = 1; break; - case 'U': { - char *strend; - vpninfo->uid = strtol(config_arg, &strend, 0); - if (strend[0]) { - struct passwd *pw = getpwnam(config_arg); - if (!pw) { - fprintf(stderr, _("Invalid user \"%s\"\n"), - config_arg); - exit(1); - } - vpninfo->uid = pw->pw_uid; - } + case 'U': + get_uids(config_arg, &vpninfo->uid, &vpninfo->gid); break; - } - case OPT_CSD_USER: { - char *strend; - vpninfo->uid_csd = strtol(config_arg, &strend, 0); - if (strend[0]) { - struct passwd *pw = getpwnam(config_arg); - if (!pw) { - fprintf(stderr, _("Invalid user \"%s\"\n"), - config_arg); - exit(1); - } - vpninfo->uid_csd = pw->pw_uid; - } + case OPT_CSD_USER: + get_uids(config_arg, &vpninfo->uid_csd, &vpninfo->gid_csd); vpninfo->uid_csd_given = 1; break; - } case OPT_CSD_WRAPPER: vpninfo->csd_wrapper = keep_config_arg(); break; diff --git a/mainloop.c b/mainloop.c index 78485021..cb45559a 100644 --- a/mainloop.c +++ b/mainloop.c @@ -22,6 +22,11 @@ #include #include #include +#ifndef _WIN32 +/* for setgroups() */ +# include +# include +#endif #include "openconnect-internal.h" @@ -122,9 +127,26 @@ static int setup_tun_device(struct openconnect_info *vpninfo) #ifndef _WIN32 if (vpninfo->uid != getuid()) { + int e; + + if (setgid(vpninfo->gid)) { + e = errno; + fprintf(stderr, _("Failed to set gid %ld: %s\n"), + (long)vpninfo->gid, strerror(e)); + return -EPERM; + } + + if (setgroups(1, &vpninfo->gid)) { + e = errno; + fprintf(stderr, _("Failed to set groups to %ld: %s\n"), + (long)vpninfo->gid, strerror(e)); + return -EPERM; + } + if (setuid(vpninfo->uid)) { - fprintf(stderr, _("Failed to set uid %ld\n"), - (long)vpninfo->uid); + e = errno; + fprintf(stderr, _("Failed to set uid %ld: %s\n"), + (long)vpninfo->uid, strerror(e)); return -EPERM; } } diff --git a/openconnect-internal.h b/openconnect-internal.h index 93b18400..17102909 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -400,6 +400,7 @@ struct openconnect_info { int xmlpost; char *dtls_ciphers; uid_t uid_csd; + gid_t gid_csd; char *csd_wrapper; int uid_csd_given; int no_http_keepalive; @@ -538,6 +539,7 @@ struct openconnect_info { char *vpnc_script; #ifndef _WIN32 uid_t uid; + gid_t gid; #endif int tun_is_up; /* whether the tun device is setup */ int use_tun_script;