added a uid_wrapper library
authorAndrew Tridgell <tridge@samba.org>
Wed, 5 Aug 2009 00:50:03 +0000 (10:50 +1000)
committerAndrew Tridgell <tridge@samba.org>
Wed, 5 Aug 2009 00:51:00 +0000 (10:51 +1000)
This library intercepts seteuid and related calls, and simulates them
in a manner similar to the nss_wrapper and socket_wrapper
libraries. This allows us to enable the vfs_unixuid NTVFS module in
the build farm, which means we are more likely to catch errors in the
token manipulation.

The simulation is not complete, but it is enough for Samba4 for
now. The major areas of incompleteness are:

 - no emulation of setreuid, setresuid or saved uids. These would be
   needed for use in Samba3

 - no emulation of ruid changing. That would also be needed for Samba3

 - no attempt to emulate file ownership changing, so code that (for
   example) tests whether st.st_uid matches geteuid() needs special
   handling

17 files changed:
lib/uid_wrapper/config.m4 [new file with mode: 0644]
lib/uid_wrapper/config.mk [new file with mode: 0644]
lib/uid_wrapper/uid_wrapper.c [new file with mode: 0644]
lib/uid_wrapper/uid_wrapper.h [new file with mode: 0644]
lib/util/config.mk
lib/util/util.c
nsswitch/config.mk
selftest/target/Samba4.pm
source4/Makefile
source4/auth/ntlm/config.mk
source4/configure.ac
source4/heimdal_build/config.h
source4/heimdal_build/internal.mk
source4/include/includes.h
source4/main.mk
source4/ntvfs/posix/pvfs_acl.c
source4/ntvfs/unixuid/config.mk

diff --git a/lib/uid_wrapper/config.m4 b/lib/uid_wrapper/config.m4
new file mode 100644 (file)
index 0000000..db6537b
--- /dev/null
@@ -0,0 +1,16 @@
+AC_ARG_ENABLE(uid-wrapper,
+AS_HELP_STRING([--enable-uid-wrapper], [Turn on uid wrapper library (default=no)]))
+
+HAVE_UID_WRAPPER=no
+
+if eval "test x$developer = xyes"; then
+       enable_uid_wrapper=yes
+fi
+
+if eval "test x$enable_uid_wrapper = xyes"; then
+        AC_DEFINE(UID_WRAPPER,1,[Use uid wrapper library])
+       HAVE_UID_WRAPPER=yes
+fi
+
+AC_SUBST(HAVE_UID_WRAPPER)
+AC_SUBST(UID_WRAPPER_OBJS)
diff --git a/lib/uid_wrapper/config.mk b/lib/uid_wrapper/config.mk
new file mode 100644 (file)
index 0000000..1bebc68
--- /dev/null
@@ -0,0 +1,9 @@
+##############################
+# Start SUBSYSTEM UID_WRAPPER
+[SUBSYSTEM::UID_WRAPPER]
+PRIVATE_DEPENDENCIES = LIBTALLOC
+# End SUBSYSTEM UID_WRAPPER
+##############################
+
+UID_WRAPPER_OBJ_FILES = $(uidwrappersrcdir)/uid_wrapper.o
+
diff --git a/lib/uid_wrapper/uid_wrapper.c b/lib/uid_wrapper/uid_wrapper.c
new file mode 100644 (file)
index 0000000..e009fa0
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+   Copyright (C) Andrew Tridgell 2009
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define UID_WRAPPER_NOT_REPLACE
+#include "includes.h"
+#include "system/passwd.h"
+#include "system/filesys.h"
+
+#ifndef _PUBLIC_
+#define _PUBLIC_
+#endif
+
+/*
+  we keep the virtualised euid/egid/groups information here
+ */
+static struct {
+       bool initialised;
+       bool enabled;
+       uid_t euid;
+       gid_t egid;
+       unsigned ngroups;
+       gid_t *groups;
+} uwrap;
+
+static void uwrap_init(void)
+{
+       if (uwrap.initialised) return;
+       uwrap.initialised = true;
+       if (getenv("UID_WRAPPER")) {
+               uwrap.enabled = true;
+       }
+}
+
+_PUBLIC_ int uwrap_seteuid(uid_t euid)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return seteuid(euid);
+       }
+       /* assume for now that the ruid stays as root */
+       uwrap.euid = euid;
+       return 0;
+}
+
+_PUBLIC_ uid_t uwrap_geteuid(void)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return geteuid();
+       }
+       return uwrap.euid;
+}
+
+_PUBLIC_ int uwrap_setegid(gid_t egid)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return setegid(egid);
+       }
+       /* assume for now that the ruid stays as root */
+       uwrap.egid = egid;
+       return 0;
+}
+
+_PUBLIC_ uid_t uwrap_getegid(void)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return getegid();
+       }
+       return uwrap.egid;
+}
+
+_PUBLIC_ int uwrap_setgroups(size_t size, const gid_t *list)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return setgroups(size, list);
+       }
+
+       talloc_free(uwrap.groups);
+       uwrap.ngroups = 0;
+
+       uwrap.groups = talloc_array(talloc_autofree_context(), gid_t, size);
+       if (uwrap.groups == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+       memcpy(uwrap.groups, list, size*sizeof(gid_t));
+       uwrap.ngroups = size;
+       return 0;
+}
+
+_PUBLIC_ int uwrap_getgroups(int size, gid_t *list)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return getgroups(size, list);
+       }
+
+       if (size > uwrap.ngroups) {
+               size = uwrap.ngroups;
+       }
+       if (size == 0) {
+               return uwrap.ngroups;
+       }
+       if (size < uwrap.ngroups) {
+               errno = EINVAL;
+               return -1;
+       }
+       memcpy(list, uwrap.groups, size*sizeof(gid_t));
+       return 0;
+}
+
+_PUBLIC_ uid_t uwrap_getuid(void)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return getuid();
+       }
+       /* we don't simulate ruid changing */
+       return 0;
+}
+
+_PUBLIC_ gid_t uwrap_getgid(void)
+{
+       uwrap_init();
+       if (!uwrap.enabled) {
+               return getgid();
+       }
+       /* we don't simulate rgid changing */
+       return 0;
+}
diff --git a/lib/uid_wrapper/uid_wrapper.h b/lib/uid_wrapper/uid_wrapper.h
new file mode 100644 (file)
index 0000000..e2df613
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+   Copyright (C) Andrew Tridgell 2009
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UID_WRAPPER_H__
+#define __UID_WRAPPER_H__
+
+#ifdef seteuid
+#undef seteuid
+#endif
+#define seteuid        uwrap_seteuid
+
+#ifdef setegid
+#undef setegid
+#endif
+#define setegid        uwrap_setegid
+
+#ifdef geteuid
+#undef geteuid
+#endif
+#define geteuid        uwrap_geteuid
+
+#ifdef getegid
+#undef getegid
+#endif
+#define getegid        uwrap_getegid
+
+#ifdef setgroups
+#undef setgroups
+#endif
+#define setgroups uwrap_setgroups
+
+#ifdef getgroups
+#undef getgroups
+#endif
+#define getgroups uwrap_getgroups
+
+#ifdef getuid
+#undef getuid
+#endif
+#define getuid uwrap_getuid
+
+#ifdef getgid
+#undef getgid
+#endif
+#define getgid uwrap_getgid
+
+#endif /* __UID_WRAPPER_H__ */
index ad39096c5654fff2f950e44a27b0a85f16031768..47e026865e7d57d6b5505f5feb34767a1e5050e0 100644 (file)
@@ -54,6 +54,7 @@ PUBLIC_HEADERS += $(addprefix $(libutilsrcdir)/, util.h \
 ASN1_UTIL_OBJ_FILES = $(libutilsrcdir)/asn1.o
 
 [SUBSYSTEM::UNIX_PRIVS]
+PRIVATE_DEPENDENCIES = UID_WRAPPER
 
 UNIX_PRIVS_OBJ_FILES = $(libutilsrcdir)/unix_privs.o
 
index f49d25865c5978756fbca063bc4b74314633a688..dea140148fa52e2e1d7561e5b25dc4202c1f9f11 100644 (file)
@@ -135,10 +135,12 @@ _PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid,
                }
                if ((st.st_uid != uid) || 
                    ((st.st_mode & 0777) != dir_perms)) {
+#ifndef UID_WRAPPER_REPLACE
                        DEBUG(0, ("invalid permissions on directory "
                                  "%s\n", dname));
                        umask(old_umask);
                        return false;
+#endif
                }
        }
        return true;
index 264032e530e30f231d357e93011db1666de7cda0..9a04f3bc37a722b2e369c849da29e04d6e4cd661 100644 (file)
@@ -30,7 +30,8 @@ PRIVATE_DEPENDENCIES = \
                LIBWBCLIENT \
                LIBTEVENT \
                UTIL_TEVENT \
-               LIBASYNC_REQ
+               LIBASYNC_REQ \
+               UID_WRAPPER
 # End BINARY nsstest
 #################################
 
index d2c11e4f321993d6de6f72c2865a7ecd8a9f57ff..db5900d0ae46bc9ad4efe1141b7e50af82109755 100644 (file)
@@ -113,6 +113,8 @@ sub check_or_start($$$)
                $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
                $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
 
+               $ENV{UID_WRAPPER} = "1";
+
                # Start slapd before samba, but with the fifo on stdin
                if (defined($self->{ldap})) {
                    $self->slapd_start($env_vars) or 
@@ -773,7 +775,6 @@ sub provision($$$$$$$)
 [tmp]
        path = $ctx->{tmpdir}
        read only = no
-       ntvfs handler = posix
        posix:sharedelay = 100000
        posix:eadb = $ctx->{lockdir}/eadb.tdb
        posix:oplocktimeout = 3
@@ -782,7 +783,6 @@ sub provision($$$$$$$)
 [test1]
        path = $ctx->{tmpdir}/test1
        read only = no
-       ntvfs handler = posix
        posix:sharedelay = 100000
        posix:eadb = $ctx->{lockdir}/eadb.tdb
        posix:oplocktimeout = 3
@@ -791,7 +791,6 @@ sub provision($$$$$$$)
 [test2]
        path = $ctx->{tmpdir}/test2
        read only = no
-       ntvfs handler = posix
        posix:sharedelay = 100000
        posix:eadb = $ctx->{lockdir}/eadb.tdb
        posix:oplocktimeout = 3
index d6ae88706665f3ec8483367b4f4b9b382d5d41b7..24e58bc37ab397185ccd0805220e6a080f97ee5f 100644 (file)
@@ -75,6 +75,7 @@ libcmdlinesrcdir := lib/cmdline
 poptsrcdir := ../lib/popt
 socketwrappersrcdir := ../lib/socket_wrapper
 nsswrappersrcdir := ../lib/nss_wrapper
+uidwrappersrcdir := ../lib/uid_wrapper
 appwebsrcdir := lib/appweb
 libstreamsrcdir := lib/stream
 libutilsrcdir := ../lib/util
index 561d14ad10fd9f2c49c98836421d8044260dcc69..cb9c3b6cc9e9a6f8348c059bea942e30e1102114 100644 (file)
@@ -57,7 +57,7 @@ auth_developer_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, auth_developer.o)
 [MODULE::auth_unix]
 INIT_FUNCTION = auth_unix_init
 SUBSYSTEM = auth
-PRIVATE_DEPENDENCIES = CRYPT PAM PAM_ERRORS NSS_WRAPPER
+PRIVATE_DEPENDENCIES = CRYPT PAM PAM_ERRORS NSS_WRAPPER UID_WRAPPER
 
 auth_unix_OBJ_FILES = $(addprefix $(authsrcdir)/ntlm/, auth_unix.o)
 
index 7c5f310aa93fa128f0b6944ab516f22c7707c432..3f10419a42d39cbb6a2816a5be5e8fec7bb82f9f 100644 (file)
@@ -125,6 +125,7 @@ m4_include(ntvfs/posix/config.m4)
 m4_include(ntvfs/unixuid/config.m4)
 m4_include(../lib/socket_wrapper/config.m4)
 m4_include(../lib/nss_wrapper/config.m4)
+m4_include(../lib/uid_wrapper/config.m4)
 m4_include(auth/config.m4)
 m4_include(kdc/config.m4)
 m4_include(ntvfs/sysdep/config.m4)
index 6a82637b2d305bfc6199043404b7316f31e4579b..8830942e30727dece1381414b7562d1448f4efec 100644 (file)
@@ -27,4 +27,9 @@
 
 #undef HAVE_KRB5_ENCRYPT_BLOCK
 
+#if defined(UID_WRAPPER) && !defined(UID_WRAPPER_REPLACE) && !defined(UID_WRAPPER_NOT_REPLACE)
+#define UID_WRAPPER_REPLACE
+#include "../uid_wrapper/uid_wrapper.h"
+#endif
+
 #endif
index c0f3b6be9903d96b5c8977a93af3e4258804b5e3..52281807b5065d7c073c26eb0a626289096d915e 100644 (file)
@@ -598,7 +598,8 @@ PRIVATE_DEPENDENCIES = \
                        HEIMDAL_ROKEN_PROGNAME \
                        HEIMDAL_ROKEN_CLOSEFROM \
                        RESOLV \
-                       LIBREPLACE_NETWORK
+                       LIBREPLACE_NETWORK \
+                       UID_WRAPPER
 # End SUBSYSTEM HEIMDAL_ROKEN
 #######################
 
index 4862a62e22c4ca9d93bfe25b91e9f486e102b034..37c6115f0f5fc326b4d19d7eedf572030f6ceac9 100644 (file)
@@ -73,4 +73,9 @@
 #define TALLOC_ABORT(reason) smb_panic(reason)
 #endif
 
+#if defined(UID_WRAPPER) && !defined(UID_WRAPPER_REPLACE) && !defined(UID_WRAPPER_NOT_REPLACE)
+#define UID_WRAPPER_REPLACE
+#include "../uid_wrapper/uid_wrapper.h"
+#endif
+
 #endif /* _INCLUDES_H */
index b4a82017c8eb14a29b260e11ceade265d2c5323f..4d7fd584f859b313f95d0a66d1c1c3ece04539d9 100644 (file)
@@ -19,6 +19,7 @@ mkinclude lib/events/config.mk
 mkinclude lib/cmdline/config.mk
 mkinclude ../lib/socket_wrapper/config.mk
 mkinclude ../lib/nss_wrapper/config.mk
+mkinclude ../lib/uid_wrapper/config.mk
 mkinclude lib/stream/config.mk
 mkinclude ../lib/util/config.mk
 mkinclude ../lib/tdr/config.mk
index 1adced44aa4e751175d9c4b1a7537a6938da8b1b..f5a00c08a8fd93a7fe09dad994db0d4b86013af2 100644 (file)
@@ -473,6 +473,14 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
                max_bits |= SEC_STD_ALL;
        }
 
+#ifdef UID_WRAPPER_REPLACE
+       /* when running with the uid wrapper, files will be created
+          owned by the ruid, but we may have a different simulated 
+          euid. We need to force the permission bits as though the 
+          files owner matches the euid */
+       max_bits |= SEC_STD_ALL;
+#endif
+
        if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
                *access_mask = max_bits;
                return NT_STATUS_OK;
index 6377657cec9e151eeea7d3f621f1a1f04509294e..105ba2f5358d28765cf22c2fff0a04958594152d 100644 (file)
@@ -3,7 +3,7 @@
 [MODULE::ntvfs_unixuid]
 INIT_FUNCTION = ntvfs_unixuid_init
 SUBSYSTEM = ntvfs
-PRIVATE_DEPENDENCIES = SAMDB NSS_WRAPPER
+PRIVATE_DEPENDENCIES = SAMDB NSS_WRAPPER UID_WRAPPER
 # End MODULE ntvfs_unixuid
 ################################################