summaryrefslogtreecommitdiff
path: root/source3/smbd/posix_acls.c
diff options
context:
space:
mode:
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);
}
/********************************************************************