[PATCH] correct dfree reporting when inherit owner is enabled

Uri Simchoni uri at samba.org
Fri Aug 12 13:49:02 UTC 2016


Hi,

The following patch set corrects the free disk reporting when "inherit
owner" is enabled.

In SMB2, the GETINFO_FS query is made relative to a path. That means
that different results as to disk size and free space can be returned,
depending on the path.

When "inherit owner" is enabled, new files get the owner of the parent
directory's owner, and hence consume that owner's quota. Therefore the
relevant quota for the free disk calculation is the quota of the
directory owner.

I once submitted this to the list as a new feature with a new parameter,
but I think this is actually the correct behavior generally, and can be
filed as a bugfix.

Review appreciated,
Uri.
-------------- next part --------------
From f28e0759c90abfdafce555cec916a8b4967d0285 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Wed, 27 Jan 2016 08:12:20 +0200
Subject: [PATCH 1/5] quotas: small cleanup

Remove an internal function from proto.h

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/smbd/proto.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 26fec95..162dbe4 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -856,7 +856,6 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn);
 
 bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 		 uint64_t *dfree, uint64_t *dsize);
-bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
 
 /* The following definitions come from smbd/reply.c  */
 
-- 
2.5.5


From a35d00dacbceeb372b9e7132c61dff5c5d5d04a4 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Thu, 14 Jan 2016 00:09:36 +0200
Subject: [PATCH 2/5] smbd: get a valid file stat to disk_quotas

Most calls to disk_quotas originate at a state with an
open file descriptor. Pass the file's stat info down to
disk_quota, so that we can avoid extra stat's and the related
error handling.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12145

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/modules/vfs_ceph.c    |  5 ++---
 source3/modules/vfs_default.c |  5 ++---
 source3/smbd/dfree.c          | 16 +++++++---------
 source3/smbd/proto.h          | 15 ++++++---------
 source3/smbd/quotas.c         | 38 ++++++++++++++++++++------------------
 source3/smbd/reply.c          | 13 ++++++++++++-
 source3/smbd/trans2.c         | 12 ++++++------
 source3/smbd/vfs.c            |  4 ++--
 8 files changed, 57 insertions(+), 51 deletions(-)

diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
index 8e11dab..59e9b9c 100644
--- a/source3/modules/vfs_ceph.c
+++ b/source3/modules/vfs_ceph.c
@@ -847,9 +847,8 @@ static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_str
 		"error %d. Falling back to slow manual allocation\n", errno));
 
 	/* available disk space is enough or not? */
-	space_avail = get_dfree_info(fsp->conn,
-				     fsp->fsp_name->base_name,
-				     &bsize, &dfree, &dsize);
+	space_avail =
+	    get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
 	/* space_avail is 1k blocks */
 	if (space_avail == (uint64_t)-1 ||
 			((uint64_t)space_to_write/1024 > space_avail) ) {
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index de5a4a3..5227e95 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1978,9 +1978,8 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
 		"error %d. Falling back to slow manual allocation\n", errno));
 
 	/* available disk space is enough or not? */
-	space_avail = get_dfree_info(fsp->conn,
-				     fsp->fsp_name->base_name,
-				     &bsize, &dfree, &dsize);
+	space_avail =
+	    get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
 	/* space_avail is 1k blocks */
 	if (space_avail == (uint64_t)-1 ||
 			((uint64_t)space_to_write/1024 > space_avail) ) {
diff --git a/source3/smbd/dfree.c b/source3/smbd/dfree.c
index fc52e51..7e58daa 100644
--- a/source3/smbd/dfree.c
+++ b/source3/smbd/dfree.c
@@ -50,7 +50,7 @@ static void disk_norm(uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
  Return number of 1K blocks available on a path and total number.
 ****************************************************************************/
 
-uint64_t sys_disk_free(connection_struct *conn, const char *path,
+uint64_t sys_disk_free(connection_struct *conn, struct smb_filename *fname,
 		       uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
 	uint64_t dfree_retval;
@@ -59,6 +59,7 @@ uint64_t sys_disk_free(connection_struct *conn, const char *path,
 	uint64_t dsize_q = 0;
 	const char *dfree_command;
 	static bool dfree_broken = false;
+	const char *path = fname->base_name;
 
 	(*dfree) = (*dsize) = 0;
 	(*bsize) = 512;
@@ -124,7 +125,7 @@ uint64_t sys_disk_free(connection_struct *conn, const char *path,
 		return (uint64_t)-1;
 	}
 
-	if (disk_quotas(conn, path, &bsize_q, &dfree_q, &dsize_q)) {
+	if (disk_quotas(conn, fname, &bsize_q, &dfree_q, &dsize_q)) {
 		uint64_t min_bsize = MIN(*bsize, bsize_q);
 
 		(*dfree) = (*dfree) * (*bsize) / min_bsize;
@@ -168,18 +169,15 @@ dfree_done:
  Potentially returned cached dfree info.
 ****************************************************************************/
 
-uint64_t get_dfree_info(connection_struct *conn,
-			const char *path,
-			uint64_t *bsize,
-			uint64_t *dfree,
-			uint64_t *dsize)
+uint64_t get_dfree_info(connection_struct *conn, struct smb_filename *fname,
+			uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
 	int dfree_cache_time = lp_dfree_cache_time(SNUM(conn));
 	struct dfree_cached_info *dfc = conn->dfree_info;
 	uint64_t dfree_ret;
 
 	if (!dfree_cache_time) {
-		return sys_disk_free(conn, path, bsize, dfree, dsize);
+		return sys_disk_free(conn, fname, bsize, dfree, dsize);
 	}
 
 	if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
@@ -190,7 +188,7 @@ uint64_t get_dfree_info(connection_struct *conn,
 		return dfc->dfree_ret;
 	}
 
-	dfree_ret = sys_disk_free(conn, path, bsize, dfree, dsize);
+	dfree_ret = sys_disk_free(conn, fname, bsize, dfree, dsize);
 
 	if (dfree_ret == (uint64_t)-1) {
 		/* Don't cache bad data. */
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 162dbe4..e591910 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -172,13 +172,10 @@ bool connections_snum_used(struct smbd_server_connection *unused, int snum);
 
 /* The following definitions come from smbd/dfree.c  */
 
-uint64_t sys_disk_free(connection_struct *conn, const char *path,
-                              uint64_t *bsize,uint64_t *dfree,uint64_t *dsize);
-uint64_t get_dfree_info(connection_struct *conn,
-			const char *path,
-			uint64_t *bsize,
-			uint64_t *dfree,
-			uint64_t *dsize);
+uint64_t sys_disk_free(connection_struct *conn, struct smb_filename *fname,
+		       uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
+uint64_t get_dfree_info(connection_struct *conn, struct smb_filename *fname,
+			uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
 
 /* The following definitions come from smbd/dir.c  */
 
@@ -854,8 +851,8 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn);
 
 /* The following definitions come from smbd/quotas.c  */
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-		 uint64_t *dfree, uint64_t *dsize);
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+		 uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
 
 /* The following definitions come from smbd/reply.c  */
 
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c
index 9d3b906..f3a727c 100644
--- a/source3/smbd/quotas.c
+++ b/source3/smbd/quotas.c
@@ -216,8 +216,8 @@ try to get the disk space from disk quotas (SunOS & Solaris2 version)
 Quota code by Peter Urbanec (amiga at cse.unsw.edu.au).
 ****************************************************************************/
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-		 uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+		 uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
 	uid_t euser_id;
 	int ret;
@@ -230,14 +230,11 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 	SMB_STRUCT_STAT sbuf;
 	SMB_DEV_T devno;
 	bool found = false;
+	const char *path = fname->base_name;
 
 	euser_id = geteuid();
 
-	if (sys_stat(path, &sbuf, false) == -1) {
-		return false;
-	}
-
-	devno = sbuf.st_ex_dev ;
+	devno = fname->st.st_ex_dev;
 	DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
 		path, (unsigned int)devno));
 	if ((fd = fopen(MNTTAB, "r")) == NULL) {
@@ -362,15 +359,16 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 try to get the disk space from disk quotas - default version
 ****************************************************************************/
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-		 uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+		 uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
   int r;
   struct dqblk D;
   uid_t euser_id;
+  const char *path = fname->base_name;
 #if !defined(AIX)
   char dev_disk[256];
-  SMB_STRUCT_STAT S;
+  SMB_STRUCT_STAT S = fname->st;
 
   /* find the block device file */
 
@@ -463,8 +461,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 
 #else /* WITH_QUOTAS */
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-		 uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+		 uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
 	(*bsize) = 512; /* This value should be ignored */
 
@@ -482,8 +480,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 /* wrapper to the new sys_quota interface
    this file should be removed later
    */
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-		 uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+		 uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
 	int r;
 	SMB_DISK_QUOTA D;
@@ -496,7 +494,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 	 */
 	ZERO_STRUCT(D);
 	id.uid = -1;
-	r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_FS_QUOTA_TYPE, id, &D);
+	r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_USER_FS_QUOTA_TYPE,
+			      id, &D);
 	if (r == -1 && errno != ENOSYS) {
 		goto try_group_quota;
 	}
@@ -507,7 +506,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 	ZERO_STRUCT(D);
 	id.uid = geteuid();
 
-	r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_QUOTA_TYPE, id, &D);
+	r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_USER_QUOTA_TYPE, id,
+			      &D);
 
 	if (r == -1) {
 		goto try_group_quota;
@@ -543,7 +543,8 @@ try_group_quota:
 	 */
 	ZERO_STRUCT(D);
 	id.gid = -1;
-	r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_FS_QUOTA_TYPE, id, &D);
+	r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_GROUP_FS_QUOTA_TYPE,
+			      id, &D);
 	if (r == -1 && errno != ENOSYS) {
 		return false;
 	}
@@ -554,7 +555,8 @@ try_group_quota:
 	id.gid = getegid();
 
 	ZERO_STRUCT(D);
-	r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_QUOTA_TYPE, id, &D);
+	r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_GROUP_QUOTA_TYPE, id,
+			      &D);
 
 	if (r == -1) {
 		return False;
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 0b7a4fb..4f1ecb1 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1573,9 +1573,20 @@ void reply_dskattr(struct smb_request *req)
 	connection_struct *conn = req->conn;
 	uint64_t ret;
 	uint64_t dfree,dsize,bsize;
+	struct smb_filename smb_fname;
 	START_PROFILE(SMBdskattr);
 
-	ret = get_dfree_info(conn, ".", &bsize, &dfree, &dsize);
+	ZERO_STRUCT(smb_fname);
+	smb_fname.base_name = discard_const_p(char, ".");
+
+	if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
+		reply_nterror(req, map_nt_error_from_unix(errno));
+		DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
+		END_PROFILE(SMBdskattr);
+		return;
+	}
+
+	ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
 	if (ret == (uint64_t)-1) {
 		reply_nterror(req, map_nt_error_from_unix(errno));
 		END_PROFILE(SMBdskattr);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 9c0660b..1775316 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -3438,8 +3438,8 @@ NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
 		{
 			uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
 			data_len = 18;
-			df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
-						&dsize);
+			df_ret = get_dfree_info(conn, &smb_fname, &bsize,
+						&dfree, &dsize);
 			if (df_ret == (uint64_t)-1) {
 				return map_nt_error_from_unix(errno);
 			}
@@ -3589,8 +3589,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
 		{
 			uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
 			data_len = 24;
-			df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
-						&dsize);
+			df_ret = get_dfree_info(conn, &smb_fname, &bsize,
+						&dfree, &dsize);
 			if (df_ret == (uint64_t)-1) {
 				return map_nt_error_from_unix(errno);
 			}
@@ -3623,8 +3623,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
 		{
 			uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
 			data_len = 32;
-			df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
-						&dsize);
+			df_ret = get_dfree_info(conn, &smb_fname, &bsize,
+						&dfree, &dsize);
 			if (df_ret == (uint64_t)-1) {
 				return map_nt_error_from_unix(errno);
 			}
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 605f9ad..45562ee 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -623,8 +623,8 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
 
 	len -= fsp->fsp_name->st.st_ex_size;
 	len /= 1024; /* Len is now number of 1k blocks needed. */
-	space_avail = get_dfree_info(conn, fsp->fsp_name->base_name,
-				     &bsize, &dfree, &dsize);
+	space_avail =
+	    get_dfree_info(conn, fsp->fsp_name, &bsize, &dfree, &dsize);
 	if (space_avail == (uint64_t)-1) {
 		return -1;
 	}
-- 
2.5.5


From 7c40ccde4856b9599aca38972eb1fcd6fd8ae6ff Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Thu, 11 Aug 2016 23:37:42 +0300
Subject: [PATCH 3/5] smbd: use owner uid for free disk calculation if owner is
 inherited

If "inherit owner" is enabled, then new files created under a
directory shall consume the quota of the directory's owner, so
the free disk calculation should take that quota into account,
not the quota of the user creating the file.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12145

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/smbd/quotas.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c
index f3a727c..2db18cd 100644
--- a/source3/smbd/quotas.c
+++ b/source3/smbd/quotas.c
@@ -506,8 +506,25 @@ bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
 	ZERO_STRUCT(D);
 	id.uid = geteuid();
 
-	r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_USER_QUOTA_TYPE, id,
-			      &D);
+	/* if new files created under this folder get this
+	 * folder's UID, then available space is governed by
+	 * the quota of the folder's UID, not the creating user.
+	 */
+	if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO &&
+	    id.uid != fname->st.st_ex_uid && id.uid != sec_initial_uid()) {
+		int save_errno;
+
+		id.uid = fname->st.st_ex_uid;
+		become_root();
+		r = SMB_VFS_GET_QUOTA(conn, fname->base_name,
+				      SMB_USER_QUOTA_TYPE, id, &D);
+		save_errno = errno;
+		unbecome_root();
+		errno = save_errno;
+	} else {
+		r = SMB_VFS_GET_QUOTA(conn, fname->base_name,
+				      SMB_USER_QUOTA_TYPE, id, &D);
+	}
 
 	if (r == -1) {
 		goto try_group_quota;
-- 
2.5.5


From 9a8e93d0f1c9768477cb67747e7e6b738b8c33e5 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Wed, 20 Jan 2016 21:54:24 +0200
Subject: [PATCH 4/5] selftest: refactor test_dfree_quota.sh - add share
 parameter

Add a share parameter to individual disk-free tests. This will
allow running tests on shares other than dfq share.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12145

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/script/tests/test_dfree_quota.sh | 47 ++++++++++++++++----------------
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/source3/script/tests/test_dfree_quota.sh b/source3/script/tests/test_dfree_quota.sh
index ab28a07..79b8d7c 100755
--- a/source3/script/tests/test_dfree_quota.sh
+++ b/source3/script/tests/test_dfree_quota.sh
@@ -99,16 +99,17 @@ setup_conf() {
 
 test_smbclient_dfree() {
 	name="$1"
-	dir="$2"
-    confs="$3"
-    expected="$4"
-	shift
+    share="$2"
+    dir="$3"
+    confs="$4"
+    expected="$5"
+    shift
     shift
     shift
     shift
     subunit_start_test "$name"
     setup_conf $confs
-	output=$($VALGRIND $smbclient //$SERVER/dfq -c "cd $dir; l" $@ 2>&1)
+    output=$($VALGRIND $smbclient //$SERVER/$share -c "cd $dir; l" $@ 2>&1)
     status=$?
     if [ "$status" = "0" ]; then
 		received=$(echo "$output" | awk '/blocks of size/ {print $1, $5, $6}')
@@ -150,39 +151,39 @@ test_smbcquotas() {
 }
 
 #basic disk-free tests
-test_smbclient_dfree "Test dfree share root SMB3 no quota" "." "conf1 ." "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test dfree subdir SMB3 no quota" "subdir1" "conf1 . conf2 subdir1" "20 1024. 10" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test dfree subdir NT1 no quota" "subdir1" "conf1 . conf2 subdir1" "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test large disk" "." "conf3 ." "1125899906842624 1024. 3000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root SMB3 no quota" dfq "." "conf1 ." "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree subdir SMB3 no quota" dfq "subdir1" "conf1 . conf2 subdir1" "20 1024. 10" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree subdir NT1 no quota" dfq "subdir1" "conf1 . conf2 subdir1" "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test large disk" dfq "." "conf3 ." "1125899906842624 1024. 3000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 #basic quota test (SMB1 only)
 test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
 
 #quota limit > disk size, remaining quota > disk free
-test_smbclient_dfree "Test dfree share root df vs quota case 1" "." "confdfq1 ." "80 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root df vs quota case 1" dfq "." "confdfq1 ." "80 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 #quota limit > disk size, remaining quota < disk free
-test_smbclient_dfree "Test dfree share root df vs quota case 2" "." "confdfq2 ." "80 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root df vs quota case 2" dfq "." "confdfq2 ." "80 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 #quota limit < disk size, remaining quota > disk free
-test_smbclient_dfree "Test dfree share root df vs quota case 3" "." "confdfq3 ." "160 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root df vs quota case 3" dfq "." "confdfq3 ." "160 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 #quota limit < disk size, remaining quota < disk free
-test_smbclient_dfree "Test dfree share root df vs quota case 4" "." "confdfq4 ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test dfree subdir df vs quota case 4" "subdir1" "confdfq4 subdir1" "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root df vs quota case 4" dfq "." "confdfq4 ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree subdir df vs quota case 4" dfq "subdir1" "confdfq4 subdir1" "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 
 #quota-->disk free special cases
-test_smbclient_dfree "Test quota->dfree soft limit" "subdir1" "slimit subdir1" "168 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test quota->dfree hard limit" "subdir1" "hlimit subdir1" "180 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test quota->dfree inode soft limit" "subdir1" "islimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test quota->dfree inode hard limit" "subdir1" "ihlimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test quota->dfree err try group" "subdir1" "trygrp1 subdir1" "240 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
-test_smbclient_dfree "Test quota->dfree no-quota try group" "subdir1" "trygrp2 subdir1" "240 1024. 16" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree soft limit" dfq "subdir1" "slimit subdir1" "168 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree hard limit" dfq "subdir1" "hlimit subdir1" "180 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree inode soft limit" dfq "subdir1" "islimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree inode hard limit" dfq "subdir1" "ihlimit subdir1" "148 1024. 0" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree err try group" dfq "subdir1" "trygrp1 subdir1" "240 1024. 20" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree no-quota try group" dfq "subdir1" "trygrp2 subdir1" "240 1024. 16" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 
 #block size different in quota and df systems
-test_smbclient_dfree "Test quota->dfree different block size" "subdir1" "blksize subdir1" "307200 1024. 307200" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test quota->dfree different block size" dfq "subdir1" "blksize subdir1" "307200 1024. 307200" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 
 #quota configured but not enforced
-test_smbclient_dfree "Test dfree share root quota not enforced" "." "notenforce ." "320 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root quota not enforced" dfq "." "notenforce ." "320 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 
 #FS quota not implemented (NFS case)
-test_smbclient_dfree "Test dfree share root FS quota not implemented" "." "nfs ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree share root FS quota not implemented" dfq "." "nfs ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 
 setup_conf
 exit $failed
-- 
2.5.5


From bb38d0488c940aa966ed5bf7ccc6c16a974b9c06 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Thu, 11 Aug 2016 23:54:22 +0300
Subject: [PATCH 5/5] selftest: add tests for dfree with inherit owner enabled

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12145

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 selftest/target/Samba3.pm                | 21 +++++++++++++++---
 source3/script/tests/test_dfree_quota.sh | 37 ++++++++++++++++++++++++++++++--
 source3/selftest/tests.py                |  2 +-
 3 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index a0996a8..8fc3204 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -614,6 +614,7 @@ sub setup_fileserver($$)
 	push(@dirs, $dfree_share_dir);
 	push(@dirs, "$dfree_share_dir/subdir1");
 	push(@dirs, "$dfree_share_dir/subdir2");
+	push(@dirs, "$dfree_share_dir/subdir3");
 
 	my $valid_users_sharedir="$share_dir/valid_users";
 	push(@dirs,$valid_users_sharedir);
@@ -1114,7 +1115,6 @@ sub createuser($$$$)
 	    warn("Unable to set password for $username account\n$cmd");
 	    return undef;
 	}
-	print "DONE\n";
 }
 
 sub provision($$$$$$$$)
@@ -1344,8 +1344,10 @@ sub provision($$$$$$$$)
 	my ($gid_nobody, $gid_nogroup, $gid_root, $gid_domusers, $gid_domadmins);
 	my ($gid_userdup, $gid_everyone);
 	my ($gid_force_user);
+	my ($uid_user1);
+	my ($uid_user2);
 
-	if ($unix_uid < 0xffff - 7) {
+	if ($unix_uid < 0xffff - 10) {
 		$max_uid = 0xffff;
 	} else {
 		$max_uid = $unix_uid;
@@ -1359,6 +1361,8 @@ sub provision($$$$$$$$)
 	$uid_pdbtest_wkn = $max_uid - 6;
 	$uid_force_user = $max_uid - 7;
 	$uid_smbget = $max_uid - 8;
+	$uid_user1 = $max_uid - 9;
+	$uid_user2 = $max_uid - 10;
 
 	if ($unix_gids[0] < 0xffff - 8) {
 		$max_gid = 0xffff;
@@ -1780,9 +1784,14 @@ sub provision($$$$$$$$)
 	wide links = yes
 [dfq]
 	path = $shrdir/dfree
-	vfs objects = fake_dfq
+	vfs objects = acl_xattr fake_acls xattr_tdb fake_dfq
 	admin users = $unix_name
 	include = $dfqconffile
+[dfq_owner]
+	path = $shrdir/dfree
+	vfs objects = acl_xattr fake_acls xattr_tdb fake_dfq
+	inherit owner = yes
+	include = $dfqconffile
 	";
 	close(CONF);
 
@@ -1808,6 +1817,8 @@ userdup:x:$uid_userdup:$gid_userdup:userdup gecos:$prefix_abs:/bin/false
 pdbtest_wkn:x:$uid_pdbtest_wkn:$gid_everyone:pdbtest_wkn gecos:$prefix_abs:/bin/false
 force_user:x:$uid_force_user:$gid_force_user:force user gecos:$prefix_abs:/bin/false
 smbget_user:x:$uid_smbget:$gid_domusers:smbget_user gecos:$prefix_abs:/bin/false
+user1:x:$uid_user1:$gid_nogroup:user1 gecos:$prefix_abs:/bin/false
+user2:x:$uid_user2:$gid_nogroup:user2 gecos:$prefix_abs:/bin/false
 ";
 	if ($unix_uid != 0) {
 		print PASSWD "root:x:$uid_root:$gid_root:root gecos:$prefix_abs:/bin/false
@@ -1882,12 +1893,16 @@ force_user:x:$gid_force_user:
 	createuser($self, $unix_name, $password, $conffile) || die("Unable to create user");
 	createuser($self, "force_user", $password, $conffile) || die("Unable to create force_user");
 	createuser($self, "smbget_user", $password, $conffile) || die("Unable to create smbget_user");
+	createuser($self, "user1", $password, $conffile) || die("Unable to create user1");
+	createuser($self, "user2", $password, $conffile) || die("Unable to create user2");
 
 	open(DNS_UPDATE_LIST, ">$prefix/dns_update_list") or die("Unable to open $$prefix/dns_update_list");
 	print DNS_UPDATE_LIST "A $server. $server_ip\n";
 	print DNS_UPDATE_LIST "AAAA $server. $server_ipv6\n";
 	close(DNS_UPDATE_LIST);
 
+	print "DONE\n";
+
 	$ret{SERVER_IP} = $server_ip;
 	$ret{SERVER_IPV6} = $server_ipv6;
 	$ret{NMBD_TEST_LOG} = "$prefix/nmbd_test.log";
diff --git a/source3/script/tests/test_dfree_quota.sh b/source3/script/tests/test_dfree_quota.sh
index 79b8d7c..6e227c4 100755
--- a/source3/script/tests/test_dfree_quota.sh
+++ b/source3/script/tests/test_dfree_quota.sh
@@ -5,7 +5,7 @@
 
 if [ $# -lt 6 ]; then
 cat <<EOF
-Usage: test_dfree_quota.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCLIENT SMBCQUOTAS
+Usage: test_dfree_quota.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCLIENT SMBCQUOTAS SMBCACLS
 EOF
 exit 1;
 fi
@@ -18,7 +18,8 @@ ENVDIR=`dirname $5`
 WORKDIR=$5/dfree
 smbclient=$6
 smbcquotas=$7
-shift 7
+smbcacls=$8
+shift 8
 failed=0
 
 CONFFILE=$ENVDIR/lib/dfq.conf
@@ -35,6 +36,8 @@ conf_lines() {
     local gid
     uid=$(id -u $USERNAME)
     gid=$(id -g $USERNAME)
+    uid1=$(id -u user1)
+    uid2=$(id -u user2)
 cat <<ABC
 conf1:df:block size = 512:disk free = 10:disk size = 20
 conf2:df:block size = 1024:disk free = 10:disk size = 20
@@ -70,6 +73,9 @@ notenforce:udflt:block size = 4096:qflags = 0
 nfs:df:block size = 4096:disk free = 10:disk size = 80
 nfs:u$uid:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 37
 nfs:udflt:nosys = 1
+confdfqp:df:block size = 4096:disk free = 10:disk size = 80
+confdfqp:u$uid1:block size = 4096:hard limit = 40:soft limit = 40:cur blocks = 36
+confdfqp:u$uid2:block size = 4096:hard limit = 41:soft limit = 41:cur blocks = 36
 ABC
 }
 
@@ -185,5 +191,32 @@ test_smbclient_dfree "Test dfree share root quota not enforced" dfq "." "notenfo
 #FS quota not implemented (NFS case)
 test_smbclient_dfree "Test dfree share root FS quota not implemented" dfq "." "nfs ." "160 1024. 12" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
 
+#test for dfree when owner is inherited
+#setup two folders with different owners
+rm -rf $WORKDIR/subdir3/*
+for d in / subdir3
+do
+    $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -D "ACL:$SERVER\user1:ALLOWED/0x0/FULL" //$SERVER/dfq $d > /dev/null 2>&1
+    $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -a "ACL:$SERVER\user1:ALLOWED/0x0/FULL" //$SERVER/dfq $d || failed=`expr $failed + 1`
+    $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -D "ACL:$SERVER\user2:ALLOWED/0x0/FULL" //$SERVER/dfq $d > /dev/null 2>&1
+    $VALGRIND $smbcacls -U$USERNAME%$PASSWORD -a "ACL:$SERVER\user2:ALLOWED/0x0/FULL" //$SERVER/dfq $d || failed=`expr $failed + 1`
+done
+
+$VALGRIND $smbclient //$SERVER/dfq -c "cd subdir3; mkdir user1" -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 > /dev/null 2>&1 || failed=`expr $failed + 1`
+$VALGRIND $smbclient //$SERVER/dfq -c "cd subdir3; mkdir user2" -Uuser2%$PASSWORD --option=clientmaxprotocol=SMB3 > /dev/null 2>&1 || failed=`expr $failed + 1`
+#test quotas
+test_smbclient_dfree "Test dfree without inherit owner - user1 at user1" \
+    dfq "subdir3/user1" "confdfqp subdir3/user1 confdfqp subdir3/user2" "160 1024. 16" \
+    -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree without inherit owner - user1 at user2" \
+    dfq "subdir3/user2" "confdfqp subdir3/user1 confdfqp subdir3/user2" "160 1024. 16" \
+    -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree with inherit owner - user1 at user1" \
+    dfq_owner "subdir3/user1" "confdfqp subdir3/user1 confdfqp subdir3/user2" "160 1024. 16" \
+    -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+test_smbclient_dfree "Test dfree with inherit owner - user1 at user2" \
+    dfq_owner "subdir3/user2" "confdfqp subdir3/user1 confdfqp subdir3/user2" "164 1024. 20" \
+    -Uuser1%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
+
 setup_conf
 exit $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 23fb37d..0a0cb08 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -184,7 +184,7 @@ for env in ["nt4_dc"]:
 for env in ["fileserver"]:
     plantestsuite("samba3.blackbox.preserve_case (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_preserve_case.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
     plantestsuite("samba3.blackbox.dfree_command (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_command.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
-    plantestsuite("samba3.blackbox.dfree_quota (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_quota.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3, smbcquotas])
+    plantestsuite("samba3.blackbox.dfree_quota (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_quota.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3, smbcquotas, smbcacls])
     plantestsuite("samba3.blackbox.valid_users (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_valid_users.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
     plantestsuite("samba3.blackbox.offline (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
     plantestsuite("samba3.blackbox.shadow_copy2 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3])
-- 
2.5.5



More information about the samba-technical mailing list