summaryrefslogtreecommitdiff
path: root/source3/smbd/posix_acls.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2006-07-19 00:13:28 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:38:13 -0500
commit0e292222c30c269c17e68acf1bbef787c1e946ed (patch)
treec15bf8b0677b624ef69ce86cd77ace20b78e8c40 /source3/smbd/posix_acls.c
parentf2faf11204e3ef0bc6a92554761cb0f0ac2a1103 (diff)
downloadsamba-0e292222c30c269c17e68acf1bbef787c1e946ed.tar.gz
samba-0e292222c30c269c17e68acf1bbef787c1e946ed.tar.bz2
samba-0e292222c30c269c17e68acf1bbef787c1e946ed.zip
r17125: Drastic problems require drastic solutions. There's
no way to get all the cases where kernel oplocks are on and we can't open the file and get the correct semantics (think about the open with truncate with an attribute only open - we'd need a vfs change to add the truncate(fname, len) call). So always drop the share mode lock before doing any real fd opens and then re-acquire it afterwards. We're already dealing with the race in the create case, and we deal with any other races in the same way. Volker, please examine *carefully* :-). This should fix the problems people reported with kernel oplocks being on. Jeremy. (This used to be commit 8171c4c404e9f382880c65daa0232f89e560f399)
Diffstat (limited to 'source3/smbd/posix_acls.c')
-rw-r--r--source3/smbd/posix_acls.c188
1 files changed, 155 insertions, 33 deletions
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 73744cf26e..d265057ac0 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -3911,7 +3911,7 @@ BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
Return -1 if no match, 0 if match and denied, 1 if match and allowed.
****************************************************************************/
-static int check_posix_acl_group_write(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+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;
@@ -3922,17 +3922,21 @@ static int check_posix_acl_group_write(connection_struct *conn, const char *fnam
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 read. */
+ /* 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)
@@ -3946,6 +3950,11 @@ static int check_posix_acl_group_write(connection_struct *conn, const char *fnam
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;
@@ -3956,16 +3965,36 @@ static int check_posix_acl_group_write(connection_struct *conn, const char *fnam
* 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;
- if (!have_write) {
- /* We don't have any group or explicit user write permission. */
- ret = -1; /* Allow caller to check "other" permissions. */
- DEBUG(10,("check_posix_acl_group_write: file %s \
-refusing write due to mask.\n", fname));
- goto done;
+ 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:
@@ -3977,9 +4006,21 @@ refusing write due to mask.\n", fname));
}
if (current_user.ut.uid == *puid) {
/* We have a uid match but we must ensure we have seen the acl mask. */
- ret = have_write;
- DEBUG(10,("check_posix_acl_group_write: file %s \
-match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "cannot write"));
+ 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;
}
@@ -4002,6 +4043,7 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
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)
@@ -4015,6 +4057,11 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
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;
@@ -4025,6 +4072,7 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
* canonicalize to 0 or 1.
*/
have_write = (have_write ? 1 : 0);
+ have_read = (have_read ? 1 : 0);
switch(tagtype) {
case SMB_ACL_GROUP:
@@ -4049,13 +4097,25 @@ match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "can
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) {
- ret = have_write;
- DEBUG(10,("check_posix_acl_group_write: file %s \
-match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
+ 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;
+ }
- /* If we don't have write permission this entry doesn't
+ 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 (have_write) {
+ if (ret) {
goto done;
}
/* But does terminate the group iteration. */
@@ -4072,12 +4132,12 @@ match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
/* If ret is -1 here we didn't match on the user entry or
supplemental group entries. */
- DEBUG(10,("check_posix_acl_group_write: ret = %d before check_stat:\n", ret));
+ DEBUG(10,("check_posix_acl_group_access: ret = %d before check_stat:\n", ret));
check_stat:
/*
- * We only check the S_IWGRP permissions if we haven't already
+ * 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
@@ -4094,16 +4154,33 @@ match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
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 == psbuf->st_gid) {
- ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
- DEBUG(10,("check_posix_acl_group_write: file %s \
-match on owning group %u -> %s.\n", fname, (unsigned int)psbuf->st_gid, ret ? "can write" : "cannot write"));
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ ret = (psbuf->st_mode & S_IRGRP) ? 1 : 0;
+ break;
+ case FILE_WRITE_DATA:
+ ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
+ break;
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+ if ((psbuf->st_mode & (S_IWGRP|S_IRGRP)) == (S_IWGRP|S_IRGRP)) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ break;
+ }
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "match on owning group %u -> %s.\n",
+ fname, (unsigned int)psbuf->st_gid,
+ ret ? "can access" : "cannot access"));
break;
}
}
if (cu_gid == (gid_t)-1) {
- DEBUG(10,("check_posix_acl_group_write: file %s \
-failed to match on user or group in token (ret = %d).\n", fname, ret ));
+ DEBUG(10,("check_posix_acl_group_access: file %s "
+ "failed to match on user or group in token (ret = %d).\n",
+ fname, ret ));
}
}
@@ -4113,7 +4190,7 @@ failed to match on user or group in token (ret = %d).\n", fname, ret ));
SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
}
- DEBUG(10,("check_posix_acl_group_write: file %s returning (ret = %d).\n", fname, ret ));
+ DEBUG(10,("check_posix_acl_group_access: file %s returning (ret = %d).\n", fname, ret ));
return ret;
}
@@ -4169,7 +4246,7 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
#endif
/* Check group or explicit user acl entry write access. */
- ret = check_posix_acl_group_write(conn, dname, &sbuf);
+ ret = check_posix_acl_group_access(conn, dname, &sbuf, FILE_WRITE_DATA);
if (ret == 0 || ret == 1) {
return ret ? True : False;
}
@@ -4179,15 +4256,23 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
}
/****************************************************************************
- Actually emulate the in-kernel access checking for write access. We need
+ 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_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
{
int ret;
+ if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
+ return False;
+ }
+ access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
+
+ 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;
@@ -4200,19 +4285,56 @@ BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_ST
}
}
- /* Check primary owner write access. */
+ /* Check primary owner access. */
if (current_user.ut.uid == psbuf->st_uid) {
- return (psbuf->st_mode & S_IWUSR) ? True : False;
+ 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;
+ }
+ }
}
- /* Check group or explicit user acl entry write access. */
- ret = check_posix_acl_group_write(conn, fname, psbuf);
+ /* Check group or explicit user acl entry access. */
+ ret = check_posix_acl_group_access(conn, fname, psbuf, access_mask);
if (ret == 0 || ret == 1) {
return ret ? True : False;
}
- /* Finally check other write access. */
- return (psbuf->st_mode & S_IWOTH) ? True : False;
+ /* Finally check other access. */
+ switch (access_mask) {
+ case FILE_READ_DATA:
+ return (psbuf->st_mode & S_IROTH) ? True : False;
+
+ case FILE_WRITE_DATA:
+ return (psbuf->st_mode & S_IWOTH) ? True : False;
+
+ default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+
+ if ((psbuf->st_mode & (S_IWOTH|S_IROTH)) == (S_IWOTH|S_IROTH)) {
+ return True;
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ 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);
}
/********************************************************************