summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>1998-07-10 01:13:16 +0000
committerJeremy Allison <jra@samba.org>1998-07-10 01:13:16 +0000
commitddb7b8a3d6cb03a36ab23816b76c7b0c16c0ab37 (patch)
treedaa4f246f67f8cd4676c00d5771a78aa216a6d39
parent769269c384f49533e335969cff0f740f8148b6ff (diff)
downloadsamba-ddb7b8a3d6cb03a36ab23816b76c7b0c16c0ab37.tar.gz
samba-ddb7b8a3d6cb03a36ab23816b76c7b0c16c0ab37.tar.bz2
samba-ddb7b8a3d6cb03a36ab23816b76c7b0c16c0ab37.zip
AIX patch from Michael Wojcik <mww@microfocus.com> adding detail
to the AIX specific (and undocumented) setpriv and setuidx calls. Jeremy. (This used to be commit 7a8d0a4ed4e07090bfe776b5544712274d2426e4)
-rw-r--r--source3/smbd/uid.c139
1 files changed, 135 insertions, 4 deletions
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index 749248ac86..358de86875 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -74,15 +74,124 @@ static BOOL become_uid(int uid)
#ifdef AIX
{
/* AIX 3 stuff - inspired by a code fragment in wu-ftpd */
+ /* MWW: This is all undocumented, of course. There's a patch to WU-ftpd
+ in the AIX FAQ which does the setpriv, then sets the gid stuff, then
+ sets uid. Since Samba separates setting the gid and setting the uid,
+ I've duplicated the setpriv code in become_gid. I've also made the
+ requisite changes to become_gid to match the WU-ftpd patch.
+
+ I believe we'll still get errors in the Samba logs. This setpriv
+ call is supposed to disable "trapdooring" on AIX - ie. normally
+ once a seteuid / setegid is done, the effective ID can't be set back
+ to what it was before. See the comments in become_root / unbecome_root.
+ I *think* that we may have to do something additional here to prevent
+ the "Can't set uid (AIX3)" messages, though - possibly change the
+ values of priv.pv_priv to keep the SET_PROC_DAC privilege, and
+ possibly SET_OBJ_DAC and SET_OBJ_STAT as well.
+
+ The pv_priv array is two longwords, and the constants in sys/priv.h
+ have values between 1 and 64, according to the comments in priv.h.
+ This strongly suggests a bit vector - but does BYPASS_DAC_WRITE
+ (#define'd to 1) mean 1<<0 or 1<<1? Unfortunately, nothing's
+ defined to 0 or 64, which would be a dead giveaway. Also, what's the
+ fullword-boundary endianness? That is, is pv_priv[0] the high or
+ the low 32 bits? Fortunately, the values used by "su" (see below)
+ don't make much sense if pv_priv[0] is the high bits. Also, based
+ on analysis of the values used by su, I concluded that, for example,
+ BYPASS_DAC_READ (defined to 2) is bit "2" counting from 1 - ie.
+ if (pv_priv[0] & (1 << (BYPASS_DAC_READ - 1))) then BYPASS_DAC_READ
+ is on. That's a bit odd, but it makes more sense than if the
+ privilege constants are meant to be taken as exponents of 2.
+
+ For analysis, I ran "su" as root under dbx, and stopped in setpriv.
+ The first argument to setpriv can be examined using
+
+ print $r3 (eg. "0x30009" = PRIV_SET|PRIV_MAXIMUM|PRIV_EFFECTIV)
+
+ the contents of the pv_priv array can be examined using
+
+ ($r4)/2X
+
+ Here's what su does:
+
+ setpriv(PRIV_SET | PRIV_INHERITED | PRIV_BEQUEATH, {0,0})
+ setpriv(PRIV_SET | PRIV_EFFECTIVE | PRIV_MAXIMUM,
+ {0x02800006, 0x00040000})
+ 0x02800006 = SET_PROC_AUDIT | SET_PROC_ENV |
+ BYPASS_DAC_EXEC | BYPASS_DAC_READ
+ 0x00040000 = TPATH_CONFIG
+ setpriv(PRIV_SET | PRIV_EFFECTIVE, {0, 0})
+
+ Analysis:
+
+ Reduce inherited privileges to none, so the child doesn't inherit
+ anything special.
+ Change su's privileges so it can execute the shell even if someone
+ has goofed up the permissions to it or to directories on the
+ search path; so it can set the process auditing characteristics
+ and privileged environment (stuff in /etc/security/environ with
+ the sysenv attribute); and so that it can set the trusted path
+ characteristics for this login.
+ Zap those privileges back off when we don't need them any more.
+
+ I'm guessing we want to keep SET_PROC_DAC in the current priv set,
+ but not in the inherited one. That is, set PRIV_INHERITED and
+ PRIV_BEQUEATH to 0. We also probably want to set PRIV_MAXIMUM and
+ PRIV_EFFECTIVE to only the privs we need, which at this point would
+ appear to be just SET_PROC_DAC. *Note*: setting PRIV_MAXIMUM
+ with any of the privilege sets higher than what you're trying to
+ set the maximum to will produce an EINVAL. For example, if we
+ try to set PRIV_MAXIMUM to SET_PROC_DAC *before* we reduce
+ PRIV_INHERITED and PRIV_BEQUEATH, it won't work. Zero out the
+ inherited privileges first.
+
+ Some experimentation with simple programs confirms that if we're
+ running with an EUID of 0 we can switch our UID/EUID back and
+ forth with setuidx - *unless* we call setpriv({0,0}, ...) first.
+ In other words, by default root has SET_PROC_DAT set, but we can
+ remove it from our privilege set. This is what we want to do for
+ child processes, I believe.
+
+ Also, calling setpriv(PRIV_SUB|PRIV_EFFECTIVE,...) with pv_priv[0]
+ set to SET_PROC_DAC (1 << (SET_PROC_DAC - 1)) will prevent an
+ EUID-root process from switching its EUID back with setuidx.
+
+ In other words, setuidx on AIX is *not* trapdoor. setuid is
+ trapdoor. We need a non-trapdoor setuid function, but we don't
+ want processes we fork to have access to it. Thus we use setuidx
+ but first we disable it for our children.
+
+ Note, however, that we can only increase our privileges (as we
+ do in the first call to setpriv) if we're EUID-root. If we
+ started out as root, and then switched to a non-root user ID,
+ that's OK; we've already set them. Just don't try to set them
+ again.
+
+ Also, I suspect that after using setpriv / setuidx / etc. here in
+ the AIX-specific code we DON'T want to fall through to the code that
+ calls setuid, etc. However, I haven't noticed any more problems with
+ the code the way it is here.
+ */
+
priv_t priv;
priv.pv_priv[0] = 0;
priv.pv_priv[1] = 0;
- if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
- &priv, sizeof(priv_t)) < 0 ||
- setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
- seteuid((uid_t)uid) < 0)
+ if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_BEQUEATH,
+ &priv, sizeof(priv_t)) < 0) {
+ DEBUG(1, ("Can't set child privileges (AIX3): %s\n", strerror(errno)));
+ }
+
+ priv.pv_priv[0] = (1 << (SET_PROC_DAC - 1));
+ if (setpriv(PRIV_SET|PRIV_EFFECTIVE|PRIV_MAXIMUM,
+ &priv, sizeof(priv_t)) < 0) {
+ DEBUG(1, ("Can't set own privileges (AIX3): %s\n", strerror(errno)));
+ }
+
+ if (setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
+ seteuid((uid_t)uid) < 0) {
DEBUG(1,("Can't set uid (AIX3)\n"));
+ }
}
#endif
@@ -125,6 +234,24 @@ static BOOL become_gid(int gid)
DEBUG(1,("WARNING: using gid %d is a security risk\n",gid));
}
+#ifdef AIX
+ {
+ /* MWW: See comment above in become_uid. */
+ priv_t priv;
+
+ priv.pv_priv[0] = 0;
+ priv.pv_priv[1] = 0;
+ if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
+ &priv, sizeof(priv_t)) < 0) {
+ DEBUG(1, ("Can't set privilege (AIX3)\n"));
+ }
+ if (setgidx(ID_REAL|ID_EFFECTIVE, (gid_t)gid) < 0 ||
+ setegid((gid_t)gid) < 0) {
+ DEBUG(1,("Can't set gid (AIX3)\n"));
+ }
+ }
+#endif
+
#ifdef USE_SETRES
if (setresgid(-1,gid,-1) != 0)
#elif defined(USE_SETFS)
@@ -169,6 +296,10 @@ BOOL become_guest(void)
pass = Get_Pwnam(lp_guestaccount(-1),True);
if (!pass) return(False);
+#ifdef AIX
+ /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before setting IDs */
+ initgroups(pass->pw_name, (gid_t)pass->pw_gid);
+#endif
ret = become_id(pass->pw_uid,pass->pw_gid);
if (!ret)