From 80810371e6ee2ed33cb22a3629373131e92a7ab4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 22 Dec 1998 02:53:06 +0000 Subject: Rather large (I'm afraid) tidyup of the setuid handling code. All setuid code now resides in the one module lib/util_sec.c. The interfaces this module exports are : void gain_root_privilage(void); - Set real/eff/saved uid's to 0. void gain_root_group_privilage(void); - Set real/eff/saved gid's to 0. int set_effective_uid(uid_t uid); - Set eff uid *only* to given value. int set_effective_gid(gid_t gid); - Set eff gid *only* to given value. BOOL become_user_permanently(uid_t uid, gid_t gid); - Set real/eff/saved uid's and gid's to uid and gid permanently - with no way back to root. Most of the quota code now uses these calls (except for a few special cases). smbd/chgpasswd.c: Ensured the dochild exits in the fork()'d child. libsmb/nmblib.c: Fix from Jasper for memory leak. Jeremy. --- source/Makefile.in | 4 +- source/auth/pass_check.c | 60 +++++------- source/configure | 2 +- source/configure.in | 2 +- source/include/config.h.in | 12 +++ source/include/proto.h | 9 +- source/lib/smbrun.c | 34 ++----- source/lib/util.c | 53 ----------- source/libsmb/nmblib.c | 4 +- source/passdb/pass_check.c | 60 +++++------- source/smbd/chgpasswd.c | 32 +++---- source/smbd/quotas.c | 37 ++++---- source/smbd/server.c | 10 +- source/smbd/uid.c | 222 ++++++++++++++++++--------------------------- source/tests/trapdoor.c | 18 +++- source/utils/smbrun.c | 28 +----- 16 files changed, 218 insertions(+), 369 deletions(-) diff --git a/source/Makefile.in b/source/Makefile.in index 190968cff18..c17b618e26e 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -98,7 +98,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/bitmap.o lib/crc32.o lib/snprintf.o \ lib/util_str.o lib/util_sid.o \ lib/util_unistr.o lib/util_file.o \ - lib/util.o lib/util_sock.o + lib/util.o lib/util_sock.o lib/util_sec.o UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \ ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o ubiqx/debugparse.o @@ -176,7 +176,7 @@ SWAT_OBJ = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \ $(PARAM_OBJ) $(PASSDB_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \ $(UBIQX_OBJ) $(LIB_OBJ) $(PRINTING_OBJ) -SMBRUN_OBJ = utils/smbrun.o +SMBRUN_OBJ = utils/smbrun.o lib/util_sec.o SMBSH_OBJ = smbwrapper/smbsh.o smbwrapper/shared.o \ $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) diff --git a/source/auth/pass_check.c b/source/auth/pass_check.c index cdbb9369688..a5a73d94f36 100644 --- a/source/auth/pass_check.c +++ b/source/auth/pass_check.c @@ -202,6 +202,7 @@ static BOOL dfs_auth(char *user,char *password) sec_passwd_rec_t passwd_rec; sec_login_auth_src_t auth_src = sec_login_auth_src_network; unsigned char dce_errstr[dce_c_error_string_len]; + gid_t egid; if (dcelogin_atmost_once) return(False); @@ -329,14 +330,16 @@ static BOOL dfs_auth(char *user,char *password) * back to being root on error though. JRA. */ - if (setregid(-1, pw->pw_gid) != 0) { + egid = getegid(); + + if (set_effective_gid(pw->pw_gid) != 0) { DEBUG(0,("Can't set egid to %d (%s)\n", pw->pw_gid, strerror(errno))); return False; } - if (setreuid(-1, pw->pw_uid) != 0) { - setgid(0); + if (set_effective_uid(pw->pw_uid) != 0) { + set_effective_gid(egid); DEBUG(0,("Can't set euid to %d (%s)\n", pw->pw_uid, strerror(errno))); return False; @@ -347,24 +350,17 @@ static BOOL dfs_auth(char *user,char *password) &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE Setup Identity for %s failed: %s\n", user,dce_errstr)); - return(False); + goto err; } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t*)&pw, &err); if (err != error_status_ok ) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr)); - - return(False); + goto err; } passwd_rec.version_number = sec_passwd_c_version_none; @@ -377,24 +373,16 @@ static BOOL dfs_auth(char *user,char *password) &auth_src, &err); if (err != error_status_ok ) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n", user,dce_errstr)); - - return(False); + goto err; } sec_login_certify_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr)); - - return(False); + goto err; } if (auth_src != sec_login_auth_src_network) { @@ -408,10 +396,7 @@ static BOOL dfs_auth(char *user,char *password) user,dce_errstr)); sec_login_purge_context(&my_dce_sec_context, &err); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); - return(False); + goto err; } sec_login_get_pwent(my_dce_sec_context, @@ -419,11 +404,7 @@ static BOOL dfs_auth(char *user,char *password) if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr)); - - /* Go back to root, JRA. */ - setuid(0); - setgid(0); - return(False); + goto err; } DEBUG(0,("DCE login succeeded for principal %s on pid %d\n", @@ -441,21 +422,24 @@ static BOOL dfs_auth(char *user,char *password) sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr)); - - return(False); + goto err; } - setuid(0); - setgid(0); + set_effective_uid(0); + set_effective_gid(0); DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time)))); dcelogin_atmost_once = 1; return (True); + +err: + + /* Go back to root, JRA. */ + set_effective_uid(0); + set_effective_gid(egid); + return(False); } void dfs_unlogin(void) diff --git a/source/configure b/source/configure index 7b871a23cdf..641ce71a727 100755 --- a/source/configure +++ b/source/configure @@ -3893,7 +3893,7 @@ else fi done -for ac_func in initgroups select rdchk getgrnam pathconf +for ac_func in initgroups select rdchk getgrnam pathconf setreuid setregid seteuid setegid do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:3900: checking for $ac_func" >&5 diff --git a/source/configure.in b/source/configure.in index 5dc298a0dd4..347dcb26763 100644 --- a/source/configure.in +++ b/source/configure.in @@ -267,7 +267,7 @@ AC_CHECK_FUNCS(waitpid getcwd strdup strtoul strerror chown chmod chroot) AC_CHECK_FUNCS(fstat strchr utime utimes getrlimit fsync execl bzero memset) AC_CHECK_FUNCS(memmove vsnprintf snprintf setsid glob strpbrk pipe crypt16 getauthuid) AC_CHECK_FUNCS(strftime sigprocmask sigblock sigaction innetgr setnetgrent getnetgrent endnetgrent) -AC_CHECK_FUNCS(initgroups select rdchk getgrnam pathconf ) +AC_CHECK_FUNCS(initgroups select rdchk getgrnam pathconf setreuid setregid seteuid setegid) AC_CHECK_FUNCS(setuidx setgroups mktime rename ftruncate stat64 fstat64 lstat64 fopen64) AC_CHECK_FUNCS(atexit grantpt dup2 lseek64 ftruncate64 readdir64) AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid yp_get_default_domain getpwanam) diff --git a/source/include/config.h.in b/source/include/config.h.in index 7b40cea96a4..c71ed429539 100644 --- a/source/include/config.h.in +++ b/source/include/config.h.in @@ -552,9 +552,15 @@ /* Define if you have the set_auth_parameters function. */ #undef HAVE_SET_AUTH_PARAMETERS +/* Define if you have the setegid function. */ +#undef HAVE_SETEGID + /* Define if you have the setenv function. */ #undef HAVE_SETENV +/* Define if you have the seteuid function. */ +#undef HAVE_SETEUID + /* Define if you have the setgroups function. */ #undef HAVE_SETGROUPS @@ -564,6 +570,12 @@ /* Define if you have the setnetgrent function. */ #undef HAVE_SETNETGRENT +/* Define if you have the setregid function. */ +#undef HAVE_SETREGID + +/* Define if you have the setreuid function. */ +#undef HAVE_SETREUID + /* Define if you have the setsid function. */ #undef HAVE_SETSID diff --git a/source/include/proto.h b/source/include/proto.h index 015edd8fbed..77228036ec2 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -296,7 +296,6 @@ void zero_free(void *p, size_t size); int set_maxfiles(int requested_max); void reg_get_subkey(char *full_keyname, char *key_name, char *subkey_name); BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name); -BOOL become_user_permanently(uid_t uid, gid_t gid); /*The following definitions come from lib/util_file.c */ @@ -311,6 +310,14 @@ BOOL setfilepwpos(void *vp, SMB_BIG_UINT tok); int getfileline(void *vp, char *linebuf, int linebuf_size); char *fgets_slash(char *s2,int maxlen,FILE *f); +/*The following definitions come from lib/util_sec.c */ + +void gain_root_privilage(void); +void gain_root_group_privilage(void); +int set_effective_uid(uid_t uid); +int set_effective_gid(gid_t gid); +BOOL become_user_permanently(uid_t uid, gid_t gid); + /*The following definitions come from lib/util_sid.c */ char *sid_to_string(pstring sidstr_out, DOM_SID *sid); diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c index 2257fa09e41..ad262c775a8 100644 --- a/source/lib/smbrun.c +++ b/source/lib/smbrun.c @@ -40,14 +40,9 @@ static BOOL setup_stdout_file(char *outfile,BOOL shared) close(1); if (shared) { - /* become root - unprivilaged users can't delete these files */ -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - setresgid(0,0,0); - setresuid(0,0,0); -#else - setuid(0); - seteuid(0); -#endif + /* become root - unprivilaged users can't delete these files */ + gain_root_privilage(); + gain_root_group_privilage(); } if(sys_stat(outfile, &st) == 0) { @@ -86,8 +81,8 @@ if shared is not set then open the file with O_EXCL set int smbrun(char *cmd,char *outfile,BOOL shared) { int fd,pid; - int uid = current_user.uid; - int gid = current_user.gid; + uid_t uid = current_user.uid; + gid_t gid = current_user.gid; /* * Lose any kernel oplock capabilities we may have. @@ -110,7 +105,7 @@ int smbrun(char *cmd,char *outfile,BOOL shared) } slprintf(syscmd,sizeof(syscmd)-1,"%s %d %d \"(%s 2>&1) > %s\"", - path,uid,gid,cmd, + path,(int)uid,(int)gid,cmd, outfile?outfile:"/dev/null"); DEBUG(5,("smbrun - running %s ",syscmd)); @@ -143,20 +138,9 @@ int smbrun(char *cmd,char *outfile,BOOL shared) /* now completely lose our privilages. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - setresgid(0,0,0); - setresuid(0,0,0); - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); -#else - setuid(0); - seteuid(0); - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); -#endif - + + become_user_permanently(uid, gid); + if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) { /* we failed to lose our privilages - do not execute diff --git a/source/lib/util.c b/source/lib/util.c index 9c8e6e92f01..3bf0a42c52a 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -2972,56 +2972,3 @@ BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name) return True; } - -/**************************************************************************** - become the specified uid - permanently ! -****************************************************************************/ -BOOL become_user_permanently(uid_t uid, gid_t gid) -{ - /* now completely lose our privilages. This is a fairly paranoid - way of doing it, but it does work on all systems that I know of */ - -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - /* - * Firstly ensure all our uids are set to root. - */ - setresgid(0,0,0); - setresuid(0,0,0); - - /* - * Now ensure we change all our gids. - */ - setresgid(gid,gid,gid); - - /* - * Now ensure all the uids are the user. - */ - setresuid(uid,uid,uid); -#else - /* - * Firstly ensure all our uids are set to root. - */ - setuid(0); - seteuid(0); - - /* - * Now ensure we change all our gids. - */ - setgid(gid); - setegid(gid); - - /* - * Now ensure all the uids are the user. - */ - setuid(uid); - seteuid(uid); -#endif - - if (getuid() != uid || geteuid() != uid || - getgid() != gid || getegid() != gid) { - /* We failed to lose our privilages. */ - return False; - } - - return(True); -} diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c index e0b6056c85a..06ef935e167 100644 --- a/source/libsmb/nmblib.c +++ b/source/libsmb/nmblib.c @@ -673,9 +673,9 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type) break; } if (!ok) { - DEBUG(10,("parse_nmb: discarding packet id = %d\n", + DEBUG(10,("read_packet: discarding packet id = %d\n", packet->packet.nmb.header.name_trn_id)); - free(packet); + free_packet(packet); return(NULL); } diff --git a/source/passdb/pass_check.c b/source/passdb/pass_check.c index cdbb9369688..a5a73d94f36 100644 --- a/source/passdb/pass_check.c +++ b/source/passdb/pass_check.c @@ -202,6 +202,7 @@ static BOOL dfs_auth(char *user,char *password) sec_passwd_rec_t passwd_rec; sec_login_auth_src_t auth_src = sec_login_auth_src_network; unsigned char dce_errstr[dce_c_error_string_len]; + gid_t egid; if (dcelogin_atmost_once) return(False); @@ -329,14 +330,16 @@ static BOOL dfs_auth(char *user,char *password) * back to being root on error though. JRA. */ - if (setregid(-1, pw->pw_gid) != 0) { + egid = getegid(); + + if (set_effective_gid(pw->pw_gid) != 0) { DEBUG(0,("Can't set egid to %d (%s)\n", pw->pw_gid, strerror(errno))); return False; } - if (setreuid(-1, pw->pw_uid) != 0) { - setgid(0); + if (set_effective_uid(pw->pw_uid) != 0) { + set_effective_gid(egid); DEBUG(0,("Can't set euid to %d (%s)\n", pw->pw_uid, strerror(errno))); return False; @@ -347,24 +350,17 @@ static BOOL dfs_auth(char *user,char *password) &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE Setup Identity for %s failed: %s\n", user,dce_errstr)); - return(False); + goto err; } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t*)&pw, &err); if (err != error_status_ok ) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr)); - - return(False); + goto err; } passwd_rec.version_number = sec_passwd_c_version_none; @@ -377,24 +373,16 @@ static BOOL dfs_auth(char *user,char *password) &auth_src, &err); if (err != error_status_ok ) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n", user,dce_errstr)); - - return(False); + goto err; } sec_login_certify_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr)); - - return(False); + goto err; } if (auth_src != sec_login_auth_src_network) { @@ -408,10 +396,7 @@ static BOOL dfs_auth(char *user,char *password) user,dce_errstr)); sec_login_purge_context(&my_dce_sec_context, &err); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); - return(False); + goto err; } sec_login_get_pwent(my_dce_sec_context, @@ -419,11 +404,7 @@ static BOOL dfs_auth(char *user,char *password) if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr)); - - /* Go back to root, JRA. */ - setuid(0); - setgid(0); - return(False); + goto err; } DEBUG(0,("DCE login succeeded for principal %s on pid %d\n", @@ -441,21 +422,24 @@ static BOOL dfs_auth(char *user,char *password) sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); - /* Go back to root, JRA. */ - setuid(0); - setgid(0); DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr)); - - return(False); + goto err; } - setuid(0); - setgid(0); + set_effective_uid(0); + set_effective_gid(0); DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time)))); dcelogin_atmost_once = 1; return (True); + +err: + + /* Go back to root, JRA. */ + set_effective_uid(0); + set_effective_gid(egid); + return(False); } void dfs_unlogin(void) diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c index 1e36f34c032..d1562466ba1 100644 --- a/source/smbd/chgpasswd.c +++ b/source/smbd/chgpasswd.c @@ -120,11 +120,8 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram, gid = pass->pw_gid; uid = pass->pw_uid; -#ifdef HAVE_SETRESUID - setresuid(0,0,0); -#else - setuid(0); -#endif + + gain_root_privilage(); /* Start new session - gets rid of controlling terminal. */ if (setsid() < 0) { @@ -184,19 +181,10 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram, /* make us completely into the right uid */ if (!as_root) { -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - setresgid(0,0,0); - setresuid(0,0,0); - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); -#else - setuid(0); - seteuid(0); - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); -#endif + if(!become_user_permanently(uid, gid)) { + DEBUG(0,("dochild: unable to permanently become uid %d, gid %d\n", (int)uid, (int)gid)); + return False; + } } DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram)); @@ -360,8 +348,12 @@ static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequenc DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid())); chstat = dochild(master, slavedev, name, passwordprogram, as_root); - if (as_root) - unbecome_root(False); + /* + * The child should never return from dochild() .... + */ + + DEBUG(0,("chat_with_program: Error: dochild() returned %d\n", chstat )); + exit(1); } if (chstat) diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c index afabb1befdf..93ec0ef3157 100644 --- a/source/smbd/quotas.c +++ b/source/smbd/quotas.c @@ -82,9 +82,9 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U } euser_id=geteuid(); - seteuid(0); + set_effective_uid(0); r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D); - seteuid(euser_id); + set_effective_uid(euser_id); /* Use softlimit to determine disk space, except when it has been exceeded */ *bsize = 1024; @@ -313,16 +313,12 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U } euser_id = geteuid(); - user_id = getuid(); - - setuid(0); /* Solaris seems to want to give info only to super-user */ - seteuid(0); + set_effective_uid(0); #if defined(SUNOS5) DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); if((file=sys_open(name, O_RDONLY,0))<0) { - setuid(user_id); /* Restore the original UID status */ - seteuid(euser_id); + set_effective_uid(euser_id); return(False); } command.op = Q_GETQUOTA; @@ -335,8 +331,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U ret = quotactl(Q_GETQUOTA, name, euser_id, &D); #endif - setuid(user_id); /* Restore the original uid status. */ - seteuid(euser_id); + set_effective_uid(euser_id); if (ret < 0) { DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) )); @@ -383,6 +378,12 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U struct dqblk D; SMB_STRUCT_STAT S; + /* + * This code presumes that OSF1 will only + * give out quota info when the real uid + * matches the effective uid. JRA. + */ + euser_id = geteuid(); user_id = getuid(); @@ -469,7 +470,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U } euser_id=geteuid(); - seteuid(0); + set_effective_uid(0); /* Use softlimit to determine disk space, except when it has been exceeded */ @@ -479,7 +480,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U { r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D); - seteuid(euser_id); /* Restore the original uid status. */ + set_effective_uid(euser_id); /* Restore the original uid status. */ if (r==-1) return(False); @@ -510,7 +511,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U { r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F); - seteuid(euser_id); /* Restore the original uid status. */ + set_effective_uid(euser_id); /* Restore the original uid status. */ if (r==-1) return(False); @@ -539,7 +540,7 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U } else { - seteuid(euser_id); /* Restore the original uid status. */ + set_effective_uid(euser_id); /* Restore the original uid status. */ return(False); } @@ -601,19 +602,15 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U uid_t user_id; gid_t egrp_id; - /* Need to be root to get quotas in FreeBSD */ - user_id = getuid(); egrp_id = getegid(); - setuid(0); - seteuid(0); + set_effective_uid(0); r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); /* As FreeBSD has group quotas, if getting the user quota fails, try getting the group instead. */ if (r) r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D); - setuid(user_id); - seteuid(euser_id); + set_effective_uid(euser_id); } #elif defined(AIX) /* AIX has both USER and GROUP quotas: diff --git a/source/smbd/server.c b/source/smbd/server.c index e016c817aa1..30ffc4b8544 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -526,14 +526,8 @@ static void usage(char *pname) /* make absolutely sure we run as root - to handle cases where people are crazy enough to have it setuid */ -#ifdef HAVE_SETRESUID - setresuid(0,0,0); -#else - setuid(0); - seteuid(0); - setuid(0); - seteuid(0); -#endif + + gain_root_privilage(); fault_setup((void (*)(void *))exit_server); CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig); diff --git a/source/smbd/uid.c b/source/smbd/uid.c index 767fc2cdb7a..90e3eafcf13 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -23,33 +23,23 @@ extern int DEBUGLEVEL; -static uid_t initial_uid; -static gid_t initial_gid; - /* what user is current? */ extern struct current_user current_user; pstring OriginalDir; /**************************************************************************** -initialise the uid routines + Initialise the uid routines. ****************************************************************************/ + void init_uid(void) { - initial_uid = current_user.uid = geteuid(); - initial_gid = current_user.gid = getegid(); - - if (initial_gid != 0 && initial_uid == 0) { -#ifdef HAVE_SETRESGID - setresgid(0,0,0); -#else - setgid(0); - setegid(0); -#endif - } + current_user.uid = geteuid(); + current_user.gid = getegid(); - initial_uid = geteuid(); - initial_gid = getegid(); + if (current_user.gid != 0 && current_user.uid == 0) { + gain_root_group_privilage(); + } current_user.conn = NULL; current_user.vuid = UID_FIELD_INVALID; @@ -57,16 +47,14 @@ void init_uid(void) dos_ChDir(OriginalDir); } - /**************************************************************************** - become the specified uid + Become the specified uid. ****************************************************************************/ + static BOOL become_uid(uid_t uid) { - if (initial_uid != 0) { - return(True); - } - + uid_t euid; + if (uid == (uid_t)-1 || ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) { static int done; if (!done) { @@ -75,95 +63,76 @@ static BOOL become_uid(uid_t uid) } } -#ifdef HAVE_TRAPDOOR_UID -#ifdef HAVE_SETUIDX - /* AIX3 has setuidx which is NOT a trapoor function (tridge) */ - if (setuidx(ID_EFFECTIVE, uid) != 0) { - if (seteuid(uid) != 0) { - DEBUG(1,("Can't set uid %d (setuidx)\n", (int)uid)); - return False; - } - } -#endif -#endif + if(set_effective_uid(uid) != 0) { + DEBUG(0,("Couldn't set effective uid to %d. Currently set to (real=%d,eff=%d). \ +Error was %s\n", (int)uid,(int)getuid(), (int)geteuid(), strerror(errno) )); -#ifdef HAVE_SETRESUID - if (setresuid(-1,uid,-1) != 0) -#else - if ((seteuid(uid) != 0) && - (setuid(uid) != 0)) -#endif - { - DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n", - (int)uid,(int)getuid(), (int)geteuid())); - if (uid > (uid_t)32000) { - DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n")); + if (uid > (uid_t)32000) + DEBUG(0,("Could be your OS doesn't like high uid values - \ +try using a different account\n")); + return(False); } - return(False); - } - if (((uid == (uid_t)-1) || ((sizeof(uid_t) == 2) && (uid == 65535))) && (geteuid() != uid)) { - DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n")); + /* Paranioa.... JRA. */ + + euid = geteuid(); + + if(euid != uid) { + DEBUG(0,("become_uid: Unable to become uid %d.\n", (int)uid )); + + if ((uid == (uid_t)-1) || ((sizeof(uid_t) == 2) && (uid == 65535))) + DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n")); + return(False); } - current_user.uid = uid; - return(True); } /**************************************************************************** - become the specified gid + Become the specified gid. ****************************************************************************/ + static BOOL become_gid(gid_t gid) { - if (initial_uid != 0) - return(True); - - if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) && (gid == (gid_t)65535))) { - DEBUG(1,("WARNING: using gid %d is a security risk\n",(int)gid)); - } + if (gid == (gid_t)-1 || ((sizeof(gid_t) == 2) && (gid == (gid_t)65535))) { + DEBUG(1,("WARNING: using gid %d is a security risk\n",(int)gid)); + } -#ifdef HAVE_SETRESGID - if (setresgid(-1,gid,-1) != 0) -#else - if (setgid(gid) != 0) -#endif - { - DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n", - (int)gid,(int)getgid(),(int)getegid())); - if (gid > 32000) { - DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n")); + if(set_effective_gid(gid) != 0) { + DEBUG(0,("Couldn't set effective gid to %d currently set to (real=%d,eff=%d)\n", + (int)gid,(int)getgid(),(int)getegid())); + if (gid > 32000) { + DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n")); + } + return(False); } - return(False); - } - current_user.gid = gid; + current_user.gid = gid; - return(True); + return(True); } /**************************************************************************** - become the specified uid and gid + Become the specified uid and gid. ****************************************************************************/ + static BOOL become_id(uid_t uid,gid_t gid) { return(become_gid(gid) && become_uid(uid)); } /**************************************************************************** -become the guest user + Become the guest user. ****************************************************************************/ + BOOL become_guest(void) { BOOL ret; static struct passwd *pass=NULL; - if (initial_uid != 0) - return(True); - if (!pass) pass = Get_Pwnam(lp_guestaccount(-1),True); if (!pass) return(False); @@ -186,8 +155,9 @@ BOOL become_guest(void) } /******************************************************************* -check if a username is OK + Check if a username is OK. ********************************************************************/ + static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) { int i; @@ -207,8 +177,9 @@ static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) /**************************************************************************** - become the user of a connection number + Become the user of a connection number. ****************************************************************************/ + BOOL become_user(connection_struct *conn, uint16 vuid) { user_struct *vuser = get_valid_user_struct(vuid); @@ -268,23 +239,21 @@ BOOL become_user(connection_struct *conn, uint16 vuid) current_user.groups = vuser->groups; } - if (initial_uid == 0) { - if (!become_gid(gid)) return(False); + if (!become_gid(gid)) return(False); #ifdef HAVE_SETGROUPS - if (!(conn && conn->ipc)) { - /* groups stuff added by ih/wreu */ - if (current_user.ngroups > 0) - if (setgroups(current_user.ngroups, - current_user.groups)<0) { - DEBUG(0,("setgroups call failed!\n")); - } - } + if (!(conn && conn->ipc)) { + /* groups stuff added by ih/wreu */ + if (current_user.ngroups > 0) + if (setgroups(current_user.ngroups, + current_user.groups)<0) { + DEBUG(0,("setgroups call failed!\n")); + } + } #endif - if (!conn->admin_user && !become_uid(uid)) - return(False); - } + if (!conn->admin_user && !become_uid(uid)) + return(False); current_user.conn = conn; current_user.vuid = vuid; @@ -296,56 +265,39 @@ BOOL become_user(connection_struct *conn, uint16 vuid) } /**************************************************************************** - unbecome the user of a connection number + Unbecome the user of a connection number. ****************************************************************************/ + BOOL unbecome_user(void ) { - if (!current_user.conn) - return(False); - - dos_ChDir(OriginalDir); - - if (initial_uid == 0) - { -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - setresuid(-1,getuid(),-1); - setresgid(-1,getgid(),-1); -#else - if (seteuid(initial_uid) != 0) - setuid(initial_uid); - setgid(initial_gid); -#endif - } + if (!current_user.conn) + return(False); -#ifdef NO_EID - if (initial_uid == 0) - DEBUG(2,("Running with no EID\n")); - initial_uid = getuid(); - initial_gid = getgid(); -#else - if (geteuid() != initial_uid) { - DEBUG(0,("Warning: You appear to have a trapdoor uid system\n")); - initial_uid = geteuid(); - } - if (getegid() != initial_gid) { - DEBUG(0,("Warning: You appear to have a trapdoor gid system\n")); - initial_gid = getegid(); - } -#endif + dos_ChDir(OriginalDir); + + set_effective_uid(0); + set_effective_gid(0); + + if (geteuid() != 0) { + DEBUG(0,("Warning: You appear to have a trapdoor uid system\n")); + } + if (getegid() != 0) { + DEBUG(0,("Warning: You appear to have a trapdoor gid system\n")); + } - current_user.uid = initial_uid; - current_user.gid = initial_gid; + current_user.uid = 0; + current_user.gid = 0; - if (dos_ChDir(OriginalDir) != 0) - DEBUG( 0, ( "chdir(%s) failed in unbecome_user\n", OriginalDir ) ); + if (dos_ChDir(OriginalDir) != 0) + DEBUG( 0, ( "chdir(%s) failed in unbecome_user\n", OriginalDir ) ); - DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", - (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); + DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", + (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); - current_user.conn = NULL; - current_user.vuid = UID_FIELD_INVALID; + current_user.conn = NULL; + current_user.vuid = UID_FIELD_INVALID; - return(True); + return(True); } static struct current_user current_user_saved; @@ -360,6 +312,7 @@ after the operation Set save_dir if you also need to save/restore the CWD ****************************************************************************/ + void become_root(BOOL save_dir) { if (become_root_depth) { @@ -380,6 +333,7 @@ When the privilaged operation is over call this Set save_dir if you also need to save/restore the CWD ****************************************************************************/ + void unbecome_root(BOOL restore_dir) { if (become_root_depth != 1) { @@ -421,5 +375,3 @@ void unbecome_root(BOOL restore_dir) become_root_depth = 0; } - - diff --git a/source/tests/trapdoor.c b/source/tests/trapdoor.c index 974db257a4e..75e04a6a927 100644 --- a/source/tests/trapdoor.c +++ b/source/tests/trapdoor.c @@ -12,13 +12,20 @@ non-trapdoor system\n"); exit(0); } -#ifdef HAVE_SETRESUID +#if defined(HAVE_SETRESUID) if (setresuid(1,1,-1) != 0) exit(1); if (getuid() != 1) exit(1); if (geteuid() != 1) exit(1); if (setresuid(0,0,0) != 0) exit(1); if (getuid() != 0) exit(1); if (geteuid() != 0) exit(1); +#elif defined(HAVE_SETREUID) && !defined(HAVE_SETEUID) + if (setreuid(1,1) != 0) exit(1); + if (getuid() != 1) exit(1); + if (geteuid() != 1) exit(1); + if (setreuid(0,0) != 0) exit(1); + if (getuid() != 0) exit(1); + if (geteuid() != 0) exit(1); #else if (seteuid(1) != 0) exit(1); if (geteuid() != 1) exit(1); @@ -26,13 +33,20 @@ non-trapdoor system\n"); if (geteuid() != 0) exit(1); #endif -#ifdef HAVE_SETRESGID +#if defined(HAVE_SETRESGID) if (setresgid(1,1,1) != 0) exit(1); if (getgid() != 1) exit(1); if (getegid() != 1) exit(1); if (setresgid(0,0,0) != 0) exit(1); if (getgid() != 0) exit(1); if (getegid() != 0) exit(1); +#elif defined(HAVE_SETREGID) && !defined(HAVE_SETEGID) + if (setresgid(1,1) != 0) exit(1); + if (getgid() != 1) exit(1); + if (getegid() != 1) exit(1); + if (setregid(0,0) != 0) exit(1); + if (getgid() != 0) exit(1); + if (getegid() != 0) exit(1); #else if (setegid(1) != 0) exit(1); if (getegid() != 1) exit(1); diff --git a/source/utils/smbrun.c b/source/utils/smbrun.c index effc4d01bfb..b7c678411c6 100644 --- a/source/utils/smbrun.c +++ b/source/utils/smbrun.c @@ -48,35 +48,17 @@ It takes 3 arguments as uid,gid,command and runs command after becoming a non-root user */ int main(int argc,char *argv[]) { - int uid,gid; + uid_t uid; + gid_t gid; close_fds(); if (argc != 4) exit(2); - uid = atoi(argv[1]); - gid = atoi(argv[2]); - - /* first become root - we may need to do this in order to lose - our privilages! */ -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - setresgid(0,0,0); - setresuid(0,0,0); -#else - setuid(0); - seteuid(0); -#endif - -#if defined(HAVE_SETRESUID) && defined(HAVE_SETRESGID) - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); -#else - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); -#endif + uid = (uid_t)atoi(argv[1]); + gid = (gid_t)atoi(argv[2]); + become_user_permanently( uid, gid); /* paranoia :-) */ if (getuid() != uid) -- cgit