From 88f0cd597773fe896f9a144088c717f05b19b90f Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 28 Jan 2009 23:46:40 +0000 Subject: droping privileges without chroot is now possible --- doc/uanytun.8.txt | 30 ++++++++-------- src/daemon.h | 101 +++++++++++++++++++++++++++++++++++++++--------------- src/options.c | 20 ++++++----- src/options.h | 2 +- src/uanytun.c | 14 ++++++-- 5 files changed, 113 insertions(+), 54 deletions(-) diff --git a/doc/uanytun.8.txt b/doc/uanytun.8.txt index 3364294..319a206 100644 --- a/doc/uanytun.8.txt +++ b/doc/uanytun.8.txt @@ -11,9 +11,9 @@ SYNOPSIS *uanytun* [ *-h|--help* ] [ *-D|--nodaemonize* ] -[ *-C|--chroot* ] [ *-u|--username* ] -[ *-H|--chroot-dir* ] +[ *-g|--groupname* ] +[ *-C|--chroot* ] [ *-P|--write-pid* ] [ *-i|--interface* ] [ *-p|--port* ] @@ -56,30 +56,32 @@ passed to the daemon: -D|--nodaemonize ~~~~~~~~~~~~~~~~ -This option instructs *uAnytun* to run in the foreground +This option instructs *uAnytun* to run in foreground instead of becoming a daemon which is the default. --C|--chroot -~~~~~~~~~~~ - -Instruct *uAnytun* to run in a chroot chail and drop privileges. The -default is not to run in chroot. - -u|--username ~~~~~~~~~~~~~~~~~~~~~~~~ -if chroot change to this user. default: nobody +run as this user. If no group is specified (*-g*) the default group of +the user is used. The default is to not drop privileges. --H|--chroot-dir -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-g|--groupname +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +run as this group. If no username is specified (*-u*) this gets ignored. +The default is to not drop privileges. + +-C|--chroot +~~~~~~~~~~~~~~~~~~ -chroot to this directory. default: /var/run/uanytun +Instruct *uAnytun* to run in a chroot jail. The default is +to not run in chroot. -P|--write-pid ~~~~~~~~~~~~~~~~~~~~~~~~~ Instruct *uAnytun* to write it's pid to this file. The default is -not to create a pid file. +to not create a pid file. -i|--interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/daemon.h b/src/daemon.h index 085f563..4ebc8cd 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -43,38 +43,83 @@ #include #include -void chrootAndDrop(const char* chrootdir, const char* username) +struct priv_info_struct { + struct passwd* pw_; + struct group* gr_; +}; +typedef struct priv_info_struct priv_info_t; + +int priv_init(priv_info_t* priv, const char* username, const char* groupname) { - if (getuid() != 0) - { - fprintf(stderr, "this programm has to be run as root in order to run in a chroot\n"); - exit(-1); - } + if(!priv) + return -1; - struct passwd *pw = getpwnam(username); - if(pw) { - if(chroot(chrootdir)) - { - fprintf(stderr, "can't chroot to %s\n", chrootdir); - exit(-1); - } - log_printf(NOTICE, "we are in chroot jail (%s) now\n", chrootdir); - if(chdir("/")) - { - fprintf(stderr, "can't change to /\n"); - exit(-1); - } - if (initgroups(pw->pw_name, pw->pw_gid) || setgid(pw->pw_gid) || setuid(pw->pw_uid)) - { - fprintf(stderr, "can't drop to user %s %d:%d\n", username, pw->pw_uid, pw->pw_gid); - exit(-1); - } - log_printf(NOTICE, "dropped user to %s %d:%d\n", username, pw->pw_uid, pw->pw_gid); + priv->pw_ = NULL; + priv->gr_ = NULL; + + priv->pw_ = getpwnam(username); + if(!priv->pw_) { + log_printf(ERR, "unkown user %s", username); + return -1; } + + if(groupname) + priv->gr_ = getgrnam(groupname); else - { - fprintf(stderr, "unknown user %s\n", username); - exit(-1); + priv->gr_ = getgrgid(priv->pw_->pw_gid); + + if(!priv->gr_) { + log_printf(ERR, "unkown group %s", groupname); + return -1; + } + + return 0; +} + +int priv_drop(priv_info_t* priv) +{ + if(!priv || !priv->pw_ || !priv->gr_) { + log_printf(ERR, "privileges not initialized properly"); + return -1; + } + + if(setgid(priv->gr_->gr_gid)) { + log_printf(ERR, "setgid('%s') failed: %m", priv->gr_->gr_name); + return -1; + } + + gid_t gr_list[1]; + gr_list[0] = priv->gr_->gr_gid; + if(setgroups (1, gr_list)) { + log_printf(ERR, "setgroups(['%s']) failed: %m", priv->gr_->gr_name); + return -1; + } + + if(setuid(priv->pw_->pw_uid)) { + log_printf(ERR, "setuid('%s') failed: %m", priv->pw_->pw_name); + return -1; + } + + log_printf(NOTICE, "dropped privileges to %s:%s", priv->pw_->pw_name, priv->gr_->gr_name); + return 0; +} + + +int do_chroot(const char* chrootdir) +{ + if(getuid() != 0) { + log_printf(ERR, "this programm has to be run as root in order to run in a chroot"); + return -1; + } + + if(chroot(chrootdir)) { + log_printf(ERR, "can't chroot to %s: %m", chrootdir); + return -1; + } + log_printf(NOTICE, "we are in chroot jail (%s) now", chrootdir); + if(chdir("/")) { + log_printf(ERR, "can't change to /: %m"); + return -1; } } diff --git a/src/options.c b/src/options.c index 9931c51..843cd4a 100644 --- a/src/options.c +++ b/src/options.c @@ -180,9 +180,9 @@ int options_parse(options_t* opt, int argc, char* argv[]) if(!strcmp(str,"-h") || !strcmp(str,"--help")) return -1; PARSE_INVERSE_BOOL_PARAM("-D","--nodaemonize", opt->daemonize_) - PARSE_BOOL_PARAM("-C","--chroot", opt->chroot_) PARSE_STRING_PARAM("-u","--username", opt->username_) - PARSE_STRING_PARAM("-H","--chroot-dir", opt->chroot_dir_) + PARSE_STRING_PARAM("-g","--groupname", opt->groupname_) + PARSE_STRING_PARAM("-C","--chroot", opt->chroot_dir_) PARSE_STRING_PARAM("-P","--write-pid", opt->pid_file_) PARSE_STRING_PARAM("-i","--interface", opt->local_addr_) PARSE_STRING_PARAM("-p","--port", opt->local_port_) @@ -236,9 +236,9 @@ void options_default(options_t* opt) opt->progname_ = strdup("uanytun"); opt->daemonize_ = 1; - opt->chroot_ = 0; - opt->username_ = strdup("nobody"); - opt->chroot_dir_ = strdup("/var/run/uanytun"); + opt->username_ = NULL; + opt->groupname_ = NULL; + opt->chroot_dir_ = NULL; opt->pid_file_ = NULL; opt->local_addr_ = NULL; opt->local_port_ = strdup("4444"); @@ -276,6 +276,8 @@ void options_clear(options_t* opt) free(opt->progname_); if(opt->username_) free(opt->username_); + if(opt->groupname_) + free(opt->groupname_); if(opt->chroot_dir_) free(opt->chroot_dir_); if(opt->pid_file_) @@ -319,9 +321,9 @@ void options_print_usage() printf("USAGE:\n"); printf("uanytun [-h|--help] prints this...\n"); printf(" [-D|--nodaemonize] don't run in background\n"); - printf(" [-C|--chroot] chroot and drop privileges\n"); - printf(" [-u|--username] if chroot change to this user\n"); - printf(" [-H|--chroot-dir] chroot to this directory\n"); + printf(" [-u|--username] change to this user\n"); + printf(" [-g|--groupname] change to this group\n"); + printf(" [-C|--chroot] chroot to this directory\n"); printf(" [-P|--write-pid] write pid to this file\n"); printf(" [-i|--interface] local ip address to bind to\n"); printf(" [-p|--port] local port to bind to\n"); @@ -352,8 +354,8 @@ void options_print(options_t* opt) { printf("progname: '%s'\n", opt->progname_); printf("daemonize: %d\n", opt->daemonize_); - printf("chroot: %d\n", opt->chroot_); printf("username: '%s'\n", opt->username_); + printf("groupname: '%s'\n", opt->groupname_); printf("chroot_dir: '%s'\n", opt->chroot_dir_); printf("pid_file: '%s'\n", opt->pid_file_); printf("local_addr: '%s'\n", opt->local_addr_); diff --git a/src/options.h b/src/options.h index b1695a8..4186055 100644 --- a/src/options.h +++ b/src/options.h @@ -38,8 +38,8 @@ struct options_struct { char* progname_; int daemonize_; - int chroot_; char* username_; + char* groupname_; char* chroot_dir_; char* pid_file_; char* local_addr_; diff --git a/src/uanytun.c b/src/uanytun.c index d1919d6..48cc020 100644 --- a/src/uanytun.c +++ b/src/uanytun.c @@ -341,6 +341,11 @@ int main(int argc, char* argv[]) exit(ret); } + priv_info_t priv; + if(opt.username_) + if(priv_init(&priv, opt.username_, opt.groupname_)) + exit(-1); + #ifndef NO_CRYPT #ifndef USE_SSL_CRYPTO ret = init_libgcrypt(); @@ -395,8 +400,13 @@ int main(int argc, char* argv[]) } } - if(opt.chroot_) - chrootAndDrop("/var/run/", "nobody"); + if(opt.chroot_dir_) + if(do_chroot(opt.chroot_dir_)) + exit(-1); + if(opt.username_) + if(priv_drop(&priv)) + exit(-1); + if(opt.daemonize_) { pid_t oldpid = getpid(); daemonize(); -- cgit v1.2.3