diff -ur stunnel-3.22/options.c stunnel-3.22-sg1/options.c --- stunnel-3.22/options.c Sun Dec 23 15:08:51 2001 +++ stunnel-3.22-sg1/options.c Wed May 15 03:55:41 2002 @@ -84,8 +84,12 @@ options.random_bytes=RANDOM_BYTES; options.output_file=NULL; options.local_ip=NULL; + options.chroot_dir=NULL; opterr=0; - while ((c = getopt(argc, argv, "A:a:cp:v:d:fTl:L:r:s:g:t:u:n:N:hC:D:O:E:R:WB:VP:S:o:I:")) != EOF) + while ((c = getopt(argc, argv, "A:a:cp:v:d:fTl:L:r:s:g:t:u:n:N:hC:D:O:E:R:WB:VP:S:o:I:" + "/:" + "i" + )) != EOF) switch (c) { case 'A': safecopy(options.cert_file,optarg); @@ -140,7 +145,13 @@ case 'f': options.option|=OPT_FOREGROUND; break; + case 'i': + options.option|=OPT_SUID_FIRST; + break; + case '/': + options.chroot_dir=optarg; + break; case 'T': options.option|=OPT_TRANSPARENT; break; if((options.option&OPT_REMOTE) && (options.option&OPT_PROGRAM) @@ -331,9 +346,12 @@ "[-S sources] " "[-t timeout] " "\n\t" - "[-u ident_username] " "[-s setuid_user] " "[-g setgid_group] " + "[-i] " + "[-/ chroot-dir] " + "\n\t" + "[-u ident_username] " "[-n protocol]" "\n\t" "[-R randfile] " @@ -388,6 +407,8 @@ #ifndef USE_WIN32 "\n -s username\tsetuid() to username in daemon mode" "\n -g groupname\tsetgid() to groupname in daemon mode" + "\n -i\t\tsetuid() and/or setgid() immediately" + "\n -/ chroot-dir\tchroot() to chroot-dir immediately after starting" "\n -P arg\tspecify pid file { dir/ | filename | none }" #endif "\n -C list\tset permitted SSL ciphers" diff -ur stunnel-3.22/prototypes.h stunnel-3.22-sg1/prototypes.h --- stunnel-3.22/prototypes.h Sun Nov 11 14:16:01 2001 +++ stunnel-3.22-sg1/prototypes.h Sun May 12 05:00:52 2002 @@ -79,6 +79,7 @@ #define OPT_REMOTE 0x20 #define OPT_TRANSPARENT 0x40 #define OPT_PTY 0x80 +#define OPT_SUID_FIRST 0x200 typedef struct { char pem[STRLEN]; /* pem (priv key/cert) filename */ @@ -111,6 +113,7 @@ int cert_defaults; char *output_file; u32 *local_ip; + char *chroot_dir; } server_options; typedef enum { diff -ur stunnel-3.22/stunnel.c stunnel-3.22-sg1/stunnel.c --- stunnel-3.22/stunnel.c Thu Dec 20 02:53:54 2001 +++ stunnel-3.22-sg1/stunnel.c Wed May 15 03:55:40 2002 @@ -54,6 +54,8 @@ static void create_pid(); static void delete_pid(); #endif +void do_setugid(char *user, char *group); +int is_alldigits(char *s); /* Socket functions */ static int listen_local(); @@ -119,6 +121,24 @@ if(!(options.option&OPT_FOREGROUND)) options.foreground=0; log_open(); + if (options.chroot_dir) + { + log(LOG_DEBUG,"chroot(%s)",options.chroot_dir); + if (chroot(options.chroot_dir) < 0) + { + ioerror("chroot"); + exit(1); + } + + if (chdir("/") < 0) + { + ioerror("chdir"); + exit(1); + } + } + if ( options.option&OPT_SUID_FIRST && + (options.setuid_user || options.setgid_group)) + do_setugid(options.setuid_user,options.setgid_group); log(LOG_NOTICE, "Using '%s' as tcpwrapper service name", options.servname); /* check if certificate exists */ @@ -371,49 +391,9 @@ exit(1); } -#ifndef USE_WIN32 - if(options.setgid_group) { - struct group *gr; - gid_t gr_list[1]; - - gr=getgrnam(options.setgid_group); - if(!gr) { - log(LOG_ERR, "Failed to get GID for group %s", - options.setgid_group); - exit(1); - } - if(setgid(gr->gr_gid)) { - sockerror("setgid"); - exit(1); - } - gr_list[0]=gr->gr_gid; - if(setgroups(1, gr_list)) { - sockerror("setgroups"); - exit(1); - } - } - - if(options.setuid_user) { - struct passwd *pw; - - pw=getpwnam(options.setuid_user); - if(!pw) { - log(LOG_ERR, "Failed to get UID for user %s", - options.setuid_user); - exit(1); - } -#ifndef USE_WIN32 - /* gotta chown that pid file, or we can't remove it. */ - if ( options.pidfile[0] && chown( options.pidfile, pw->pw_uid, -1) ) { - log(LOG_ERR, "Failed to chown pidfile %s", options.pidfile); - } -#endif - if(setuid(pw->pw_uid)) { - sockerror("setuid"); - exit(1); - } - } -#endif /* USE_WIN32 */ + if (!(options.option&OPT_SUID_FIRST) && + (options.setuid_user || options.setgid_group)) + do_setugid(options.setuid_user,options.setgid_group); return ls; } @@ -682,3 +705,78 @@ return retval; } +void do_setugid(char *user, char *group) + { + uid_t uid; + gid_t gid; + +#ifndef USE_WIN32 + if(group) { + struct group *gr; + gid_t gr_list[1]; + + if (is_alldigits(group)) + { + gid=atoi(group); + } + else + { + gr=getgrnam(group); + if(!gr) { + log(LOG_ERR, "Failed to get GID for group %s", + options.setgid_group); + exit(1); + } + gid = gr->gr_gid; + } + + if(setgid(gid)) { + sockerror("setgid"); + exit(1); + } + gr_list[0]=gid; + if(setgroups(1, gr_list)) { + sockerror("setgroups"); + exit(1); + } + } +#endif + + if(user) { + struct passwd *pw; + + if (is_alldigits(user)) + { + uid = atoi(user); + } + else + { + pw=getpwnam(options.setuid_user); + if(!pw) { + log(LOG_ERR, "Failed to get UID for user %s", + options.setuid_user); + exit(1); + } + uid=pw->pw_uid; + } + +#ifndef USE_WIN32 + /* gotta chown that pid file, or we can't remove it. */ + if ( options.pidfile[0] && chown( options.pidfile, uid, -1) ) { + log(LOG_ERR, "Failed to chown pidfile %s", options.pidfile); + } +#endif + if(setuid(uid)) { + sockerror("setuid"); + exit(1); + } + } + } + +int is_alldigits(char *s) { + while (*s) + if (!isdigit(*s++)) + return 0; + return 1; +} +