accessx-check-access-permissions   [plain text]


Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -914,6 +914,7 @@ main() {
 	default_shared_modules="$default_shared_modules vfs_darwinacl"
 
  	AC_CHECK_FUNCS(pthread_setugid_np)
+	AC_CHECK_FUNCS(accessx_np)
 
 	;;
     *hurd*)
Index: samba/source/smbd/posix_acls.c
===================================================================
--- samba/source/smbd/posix_acls.c.orig
+++ samba/source/smbd/posix_acls.c
@@ -4,6 +4,8 @@
    Copyright (C) Jeremy Allison 1994-2000.
    Copyright (C) Andreas Gruenbacher 2002.
 
+   Copyright (C) 2008 Apple Inc. All rights reserved.
+
    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 2 of the License, or
@@ -4237,6 +4239,94 @@ static BOOL can_access_file_acl(struct c
 	return result;
 }
 
+#if HAVE_ACCESSX_NP
+/* XXX This should really be in a new VFS operation, SMB_VFS_ACCESS. */
+static const struct
+{
+	int accessx;
+	int ntperm;
+} nt_accessx_table[] =
+{
+	{ _READ_OK,	FILE_READ_DATA },
+	{ _WRITE_OK,	FILE_WRITE_DATA },
+	{ _EXECUTE_OK,	FILE_EXECUTE },
+	{ _DELETE_OK,	STD_RIGHT_DELETE_ACCESS },
+	{ _APPEND_OK,	FILE_APPEND_DATA },
+	{ _RMFILE_OK,	FILE_DELETE_CHILD },
+	{ _RATTR_OK,	FILE_READ_ATTRIBUTES },
+	{ _WATTR_OK,	FILE_READ_EA },
+	{ _REXT_OK,	FILE_WRITE_ATTRIBUTES },
+	{ _WEXT_OK,	FILE_WRITE_EA },
+	{ _RPERM_OK,	STD_RIGHT_READ_CONTROL_ACCESS },
+	{ _WPERM_OK,	STD_RIGHT_WRITE_DAC_ACCESS },
+	{ _CHOWN_OK,	STD_RIGHT_WRITE_OWNER_ACCESS },
+};
+
+static uint32_t accessx_convert_mask(uint32_t access_mode)
+{
+	uint32_t accessx_mode = 0;
+	unsigned i;
+
+	for (i = 0; i < ARRAY_SIZE(nt_accessx_table); ++i) {
+		uint32_t p = nt_accessx_table[i].accessx;
+
+		if (access_mode & p) {
+			accessx_mode |= nt_accessx_table[i].ntperm;
+		}
+	}
+
+	return accessx_mode;
+}
+
+static BOOL accessx_check(const char * fname, uint32_t access_mode)
+{
+	uint8_t * accessx_buffer;
+	size_t fname_size;
+	struct accessx_descriptor * desc0;
+	int err0 = 0;
+	int err;
+
+	/* For streams, do the access check on the base file path, since the
+	 * alternate streams do not have separate security information.
+	 */
+	if (is_ntfs_stream_name(fname)) {
+	    const char * pivot = strchr_m(fname, ':');
+
+	    /* Include the ':' in the name size so that we can NULL it out
+	     * later.
+	     */
+	    fname_size = pivot - fname + 1;
+	} else {
+	    fname_size = strlen(fname) + 1;
+	}
+
+	accessx_buffer =
+	    alloca(sizeof(struct accessx_descriptor) + fname_size);
+	memcpy(accessx_buffer + sizeof(struct accessx_descriptor),
+		fname, fname_size);
+	accessx_buffer[sizeof(struct accessx_descriptor) + fname_size - 1] = '\0';
+
+	desc0 = (struct accessx_descriptor *)accessx_buffer;
+	ZERO_STRUCTP(desc0);
+
+	desc0->ad_flags = accessx_convert_mask(access_mode);
+	desc0->ad_name_offset = sizeof(struct accessx_descriptor);
+
+	err = accessx_np((struct accessx_descriptor *)accessx_buffer,
+		sizeof(struct accessx_descriptor) + fname_size,
+		&err0, (uid_t) -1 /* ignored */);
+	if (err == -1) {
+		DEBUG(0, ("accessx_np(%s, %#x) failed: %s\n",
+			fname, access_mode, strerror(errno)));
+		return False;
+	}
+
+	/* Access granted if errno was 0. */
+	return (err0 == 0);
+}
+
+#endif /* HAVE_ACCESSX_NP */
+
 /****************************************************************************
  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.
@@ -4262,6 +4352,11 @@ BOOL can_delete_file_in_directory(connec
 	if (!S_ISDIR(sbuf.st_mode)) {
 		return False;
 	}
+
+#if HAVE_ACCESSX_NP
+	return accessx_check(dname, FILE_DELETE_CHILD);
+#endif
+
 	if (current_user.ut.uid == 0 || conn->admin_user) {
 		/* I'm sorry sir, I didn't know you were root... */
 		return True;
@@ -4318,6 +4413,10 @@ BOOL can_access_file(connection_struct *
 	DEBUG(10,("can_access_file: requesting 0x%x on file %s\n",
 		(unsigned int)access_mask, fname ));
 
+#if HAVE_ACCESSX_NP
+	return accessx_check(fname, access_mask);
+#endif
+
 	if (current_user.ut.uid == 0 || conn->admin_user) {
 		/* I'm sorry sir, I didn't know you were root... */
 		return True;
Index: samba/source/smbd/open.c
===================================================================
--- samba/source/smbd/open.c.orig
+++ samba/source/smbd/open.c
@@ -1520,10 +1520,15 @@ NTSTATUS open_file_ntcreate(connection_s
 				can_access_mask = FILE_READ_DATA;
 			}
 
+#if HAVE_ACCESSX_NP
+			can_access = can_access_file(conn, fname, psbuf,
+						    can_access_mask);
+#else
 			if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) ||
 			    !can_access_file(conn,fname,psbuf,can_access_mask)) {
 				can_access = False;
 			}
+#endif
 
 			/* 
 			 * If we're returning a share violation, ensure we