[SCM] Samba Shared Repository - branch v3-2-test updated - initial-v3-2-unstable-215-g9dd18bb

Michael Adam obnox at samba.org
Tue Nov 6 18:36:45 GMT 2007


The branch, v3-2-test has been updated
       via  9dd18bb534bca6b5de6cad9580b48681b36c0832 (commit)
       via  c61b4222d30288add216fac4da3cfaa537f5cd01 (commit)
       via  6f961a23de745aba5dcd4585b731e651b8cbeef4 (commit)
      from  7b582af2107bed3b864bb408b5c9bcce4b8e4c72 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-2-test


- Log -----------------------------------------------------------------
commit 9dd18bb534bca6b5de6cad9580b48681b36c0832
Author: Michael Adam <obnox at samba.org>
Date:   Fri Oct 26 19:50:55 2007 +0200

    Move some access check functions that are not posix-acl specific
    to a new source file of their own.
    
    Michael

commit c61b4222d30288add216fac4da3cfaa537f5cd01
Author: Michael Adam <obnox at samba.org>
Date:   Thu Oct 25 13:32:56 2007 +0200

    Don't repeat fast-pathing...
    
    Michael

commit 6f961a23de745aba5dcd4585b731e651b8cbeef4
Author: Michael Adam <obnox at samba.org>
Date:   Sat Oct 20 02:17:07 2007 +0200

    This is a proposed patch for Bug #5023.
    
    The three can_* access check functions in smbd/posix_acls.c that are used in
    smbd/open.c and smbd/nttrans.c explicitly called check_posix_acl_group_access()
    
    This lead to errors with nfsv4 acls (ZFS and GPFS).
    
    This changes the can_* functions to get the nt_acl via VFS layer and call
    se_access_check on that. It also removes check_posix_acl_group_access()
    which has no more callers.
    
    NOTE: The can_* functions should really not be in smbd/posix_acls.c but
    in a separate file (I propose smbd/access.c).
    
    Michael

-----------------------------------------------------------------------

Summary of changes:
 source/Makefile.in        |    1 +
 source/smbd/file_access.c |  239 ++++++++++++++++++++++++
 source/smbd/posix_acls.c  |  442 ---------------------------------------------
 3 files changed, 240 insertions(+), 442 deletions(-)
 create mode 100644 source/smbd/file_access.c


Changeset truncated at 500 lines:

diff --git a/source/Makefile.in b/source/Makefile.in
index baa1828..ef3a0c9 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -542,6 +542,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
 	       smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
 	       $(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
 	       smbd/dmapi.o \
+	       smbd/file_access.o \
 	       $(MANGLE_OBJ) @VFS_STATIC@
 
 SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
diff --git a/source/smbd/file_access.c b/source/smbd/file_access.c
new file mode 100644
index 0000000..189fcbb
--- /dev/null
+++ b/source/smbd/file_access.c
@@ -0,0 +1,239 @@
+/*
+   Unix SMB/CIFS implementation.
+   Check access to files based on security descriptors.
+   Copyright (C) Jeremy Allison 2005-2006.
+   Copyright (C) Michael Adam 2007.
+
+   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/>.
+*/
+
+#include "includes.h"
+
+extern struct current_user current_user;
+
+#undef  DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
+/****************************************************************************
+ Helper function that gets a security descriptor by connection and
+ file name.
+ NOTE: This is transitional, in the sense that SMB_VFS_GET_NT_ACL really
+ should *not* get a files_struct pointer but a connection_struct ptr
+ (automatic by the vfs handle) and the file name and _use_ that!
+****************************************************************************/
+static NTSTATUS conn_get_nt_acl(TALLOC_CTX *mem_ctx,
+				struct connection_struct *conn,
+				const char *fname,
+				SMB_STRUCT_STAT *psbuf,
+				struct security_descriptor **psd)
+{
+	NTSTATUS status;
+	struct files_struct *fsp = NULL;
+	struct security_descriptor *secdesc = NULL;
+	size_t secdesc_size;
+
+	if (!VALID_STAT(*psbuf)) {
+		if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+			return map_nt_error_from_unix(errno);
+		}
+	}
+
+	/* fake a files_struct ptr: */
+
+	status = open_file_stat(conn, NULL, fname, psbuf, &fsp);
+	/* Perhaps it is a directory */
+	if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
+		status = open_directory(conn, NULL, fname, psbuf,
+					READ_CONTROL_ACCESS,
+					FILE_SHARE_READ|FILE_SHARE_WRITE,
+					FILE_OPEN,
+					0,
+					FILE_ATTRIBUTE_DIRECTORY,
+					NULL, &fsp);
+	}
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(3, ("Unable to open file %s: %s\n", fname,
+			  nt_errstr(status)));
+		return status;
+	}
+
+	secdesc_size = SMB_VFS_GET_NT_ACL(fsp, fname,
+					  (OWNER_SECURITY_INFORMATION |
+					   GROUP_SECURITY_INFORMATION |
+					   DACL_SECURITY_INFORMATION),
+					  &secdesc);
+	if (secdesc_size == 0) {
+		DEBUG(5, ("Unable to get NT ACL for file %s\n", fname));
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	*psd = talloc_move(mem_ctx, &secdesc);
+	close_file(fsp, NORMAL_CLOSE);
+	return NT_STATUS_OK;
+}
+
+static bool can_access_file_acl(struct connection_struct *conn,
+				const char * fname, SMB_STRUCT_STAT *psbuf,
+				uint32_t access_mask)
+{
+	bool result;
+	NTSTATUS status;
+	uint32_t access_granted;
+	struct security_descriptor *secdesc = NULL;
+
+	status = conn_get_nt_acl(talloc_tos(), conn, fname, psbuf, &secdesc);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status)));
+		return false;
+	}
+
+	result = se_access_check(secdesc, current_user.nt_user_token,
+				 access_mask, &access_granted, &status);
+	TALLOC_FREE(secdesc);
+	return result;
+}
+
+/****************************************************************************
+ Actually emulate the in-kernel access checking for delete access. We need
+ this to successfully return ACCESS_DENIED on a file open for delete access.
+****************************************************************************/
+
+bool can_delete_file_in_directory(connection_struct *conn, const char *fname)
+{
+	SMB_STRUCT_STAT sbuf;
+	TALLOC_CTX *ctx = talloc_tos();
+	char *dname = NULL;
+
+	if (!CAN_WRITE(conn)) {
+		return False;
+	}
+
+	/* Get the parent directory permission mask and owners. */
+	if (!parent_dirname_talloc(ctx,
+				fname,
+				&dname,
+				NULL)) {
+		return False;
+	}
+	if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
+		return False;
+	}
+
+	/* fast paths first */
+
+	if (!S_ISDIR(sbuf.st_mode)) {
+		return False;
+	}
+	if (current_user.ut.uid == 0 || conn->admin_user) {
+		/* I'm sorry sir, I didn't know you were root... */
+		return True;
+	}
+
+	/* Check primary owner write access. */
+	if (current_user.ut.uid == sbuf.st_uid) {
+		return (sbuf.st_mode & S_IWUSR) ? True : False;
+	}
+
+#ifdef S_ISVTX
+	/* sticky bit means delete only by owner or root. */
+	if (sbuf.st_mode & S_ISVTX) {
+		SMB_STRUCT_STAT sbuf_file;
+		if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
+			if (errno == ENOENT) {
+				/* If the file doesn't already exist then
+				 * yes we'll be able to delete it. */
+				return True;
+			}
+			return False;
+		}
+		/*
+		 * Patch from SATOH Fumiyasu <fumiyas at miraclelinux.com>
+		 * for bug #3348. Don't assume owning sticky bit
+		 * directory means write access allowed.
+		 */
+		if (current_user.ut.uid != sbuf_file.st_uid) {
+			return False;
+		}
+	}
+#endif
+
+	/* now for ACL checks */
+
+	return can_access_file_acl(conn, dname, &sbuf, FILE_WRITE_DATA);
+}
+
+/****************************************************************************
+ Actually emulate the in-kernel access checking for read/write access. We need
+ this to successfully check for ability to write for dos filetimes.
+ Note this doesn't take into account share write permissions.
+****************************************************************************/
+
+bool can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
+{
+	if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
+		return False;
+	}
+	access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
+
+	/* some fast paths first */
+
+	DEBUG(10,("can_access_file: requesting 0x%x on file %s\n",
+		(unsigned int)access_mask, fname ));
+
+	if (current_user.ut.uid == 0 || conn->admin_user) {
+		/* I'm sorry sir, I didn't know you were root... */
+		return True;
+	}
+
+	if (!VALID_STAT(*psbuf)) {
+		/* Get the file permission mask and owners. */
+		if(SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+			return False;
+		}
+	}
+
+	/* Check primary owner access. */
+	if (current_user.ut.uid == psbuf->st_uid) {
+		switch (access_mask) {
+			case FILE_READ_DATA:
+				return (psbuf->st_mode & S_IRUSR) ? True : False;
+
+			case FILE_WRITE_DATA:
+				return (psbuf->st_mode & S_IWUSR) ? True : False;
+
+			default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+
+				if ((psbuf->st_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) {
+					return True;
+				} else {
+					return False;
+				}
+		}
+	}
+
+	/* now for ACL checks */
+
+	return can_access_file_acl(conn, fname, psbuf, access_mask);
+}
+
+/****************************************************************************
+ Userspace check for write access.
+ Note this doesn't take into account share write permissions.
+****************************************************************************/
+
+bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+{
+	return can_access_file(conn, fname, psbuf, FILE_WRITE_DATA);
+}
+
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index 6422bad..6e7dae4 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -4125,448 +4125,6 @@ bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
 	return True;
 }
 
-/****************************************************************************
- Check for POSIX group ACLs. If none use stat entry.
- Return -1 if no match, 0 if match and denied, 1 if match and allowed.
-****************************************************************************/
-
-static int check_posix_acl_group_access(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
-{
-	SMB_ACL_T posix_acl = NULL;
-	int entry_id = SMB_ACL_FIRST_ENTRY;
-	SMB_ACL_ENTRY_T entry;
-	int i;
-	bool seen_mask = False;
-	bool seen_owning_group = False;
-	int ret = -1;
-	gid_t cu_gid;
-
-	DEBUG(10,("check_posix_acl_group_access: requesting 0x%x on file %s\n",
-		(unsigned int)access_mask, fname ));
-
-	if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
-		goto check_stat;
-	}
-
-	/* First ensure the group mask allows group access. */
-	/* Also check any user entries (these take preference over group). */
-
-	while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
-		SMB_ACL_TAG_T tagtype;
-		SMB_ACL_PERMSET_T permset;
-		int have_write = -1;
-		int have_read = -1;
-
-		/* get_next... */
-		if (entry_id == SMB_ACL_FIRST_ENTRY)
-			entry_id = SMB_ACL_NEXT_ENTRY;
-
-		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
-			goto check_stat;
-		}
-
-		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
-			goto check_stat;
-		}
-
-		have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
-		if (have_read == -1) {
-			goto check_stat;
-		}
-
-		have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
-		if (have_write == -1) {
-			goto check_stat;
-		}
-
-		/*
-		 * Solaris returns 2 for this if write is available.
-		 * canonicalize to 0 or 1.
-		 */	
-		have_write = (have_write ? 1 : 0);
-		have_read = (have_read ? 1 : 0);
-
-		switch(tagtype) {
-			case SMB_ACL_MASK:
-				seen_mask = True;
-				switch (access_mask) {
-					case FILE_READ_DATA:
-						if (!have_read) {
-							ret = -1;
-							DEBUG(10,("check_posix_acl_group_access: file %s "
-								"refusing read due to mask.\n", fname));
-							goto done;
-						}
-						break;
-					case FILE_WRITE_DATA:
-						if (!have_write) {
-							ret = -1;
-							DEBUG(10,("check_posix_acl_group_access: file %s "
-								"refusing write due to mask.\n", fname));
-							goto done;
-						}
-						break;
-					default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-						if (!have_write || !have_read) {
-							ret = -1;
-							DEBUG(10,("check_posix_acl_group_access: file %s "
-								"refusing read/write due to mask.\n", fname));
-							goto done;
-						}
-						break;
-				}
-				break;
-			case SMB_ACL_USER:
-			{
-				/* Check against current_user.ut.uid. */
-				uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
-				if (puid == NULL) {
-					goto check_stat;
-				}
-				if (current_user.ut.uid == *puid) {
-					/* We have a uid match but we must ensure we have seen the acl mask. */
-					switch (access_mask) {
-						case FILE_READ_DATA:
-							ret = have_read;
-							break;
-						case FILE_WRITE_DATA:
-							ret = have_write;
-							break;
-						default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-							ret = (have_write & have_read);
-							break;
-					}
-					DEBUG(10,("check_posix_acl_group_access: file %s "
-						"match on user %u -> %s.\n",
-						fname, (unsigned int)*puid,
-						ret ? "can access" : "cannot access"));
-					if (seen_mask) {
-						goto done;
-					}
-				}
-				break;
-			}
-			default:
-				continue;
-		}
-	}
-
-	/* If ret is anything other than -1 we matched on a user entry. */
-	if (ret != -1) {
-		goto done;
-	}
-
-	/* Next check all group entries. */
-	entry_id = SMB_ACL_FIRST_ENTRY;
-	while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
-		SMB_ACL_TAG_T tagtype;
-		SMB_ACL_PERMSET_T permset;
-		int have_write = -1;
-		int have_read = -1;
-
-		/* get_next... */
-		if (entry_id == SMB_ACL_FIRST_ENTRY)
-			entry_id = SMB_ACL_NEXT_ENTRY;
-
-		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
-			goto check_stat;
-		}
-
-		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
-			goto check_stat;
-		}
-
-		have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
-		if (have_read == -1) {
-			goto check_stat;
-		}
-
-		have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
-		if (have_write == -1) {
-			goto check_stat;
-		}
-
-		/*
-		 * Solaris returns 2 for this if write is available.
-		 * canonicalize to 0 or 1.
-		 */	
-		have_write = (have_write ? 1 : 0);
-		have_read = (have_read ? 1 : 0);
-
-		switch(tagtype) {
-			case SMB_ACL_GROUP:
-			case SMB_ACL_GROUP_OBJ:
-			{
-				gid_t *pgid = NULL;
-
-				if (tagtype == SMB_ACL_GROUP) {
-					pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
-				} else {
-					seen_owning_group = True;
-					pgid = &psbuf->st_gid;
-				}
-				if (pgid == NULL) {
-					goto check_stat;
-				}
-
-				/*
-				 * Does it match the current effective group
-				 * or supplementary groups ?
-				 */
-				for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
-							cu_gid = get_current_user_gid_next(&i)) {
-					if (cu_gid == *pgid) {
-						switch (access_mask) {
-							case FILE_READ_DATA:
-								ret = have_read;
-								break;
-							case FILE_WRITE_DATA:
-								ret = have_write;
-								break;
-							default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-								ret = (have_write & have_read);
-								break;
-						}
-
-						DEBUG(10,("check_posix_acl_group_access: file %s "
-							"match on group %u -> can access.\n",
-							fname, (unsigned int)cu_gid ));
-
-						/* If we don't have access permission this entry doesn't
-							terminate the enumeration of the entries. */
-						if (ret) {
-							goto done;
-						}
-						/* But does terminate the group iteration. */
-						break;
-					}
-				}
-				break;
-			}
-			default:
-				continue;
-		}
-	}
-
-	/* If ret is -1 here we didn't match on the user entry or
-	   supplemental group entries. */
-	
-	DEBUG(10,("check_posix_acl_group_access: ret = %d before check_stat:\n", ret));
-
-  check_stat:
-
-	/*
-	 * We only check the S_I[RW]GRP permissions if we haven't already
-	 * seen an owning group SMB_ACL_GROUP_OBJ ace entry. If there is an
-	 * SMB_ACL_GROUP_OBJ ace entry then the group bits in st_gid are
-	 * the same as the SMB_ACL_MASK bits, not the SMB_ACL_GROUP_OBJ


-- 
Samba Shared Repository


More information about the samba-cvs mailing list