summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/param/loadparm.c4
-rw-r--r--source3/smbd/posix_acls.c161
2 files changed, 131 insertions, 34 deletions
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 49e63666c9..ae5af60e46 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -437,6 +437,7 @@ typedef struct
BOOL bEASupport;
BOOL bAclCheckPermissions;
BOOL bAclMapFullControl;
+ BOOL bAclGroupControl;
int iallocation_roundup_size;
int iAioReadSize;
int iAioWriteSize;
@@ -569,6 +570,7 @@ static service sDefault = {
False, /* bEASupport */
True, /* bAclCheckPermissions */
True, /* bAclMapFullControl */
+ False, /* bAclGroupControl */
SMB_ROUNDUP_ALLOCATION_SIZE, /* iallocation_roundup_size */
0, /* iAioReadSize */
0, /* iAioWriteSize */
@@ -873,6 +875,7 @@ static struct parm_struct parm_table[] = {
{"writable", P_BOOLREV, P_LOCAL, &sDefault.bRead_only, NULL, NULL, FLAG_HIDE},
{"acl check permissions", P_BOOL, P_LOCAL, &sDefault.bAclCheckPermissions, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
+ {"acl group control", P_BOOL, P_LOCAL, &sDefault.bAclGroupControl, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
{"acl map full control", P_BOOL, P_LOCAL, &sDefault.bAclMapFullControl, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
{"create mask", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
{"create mode", P_OCTAL, P_LOCAL, &sDefault.iCreate_mask, NULL, NULL, FLAG_HIDE},
@@ -1979,6 +1982,7 @@ FN_LOCAL_BOOL(lp_profile_acls, bProfileAcls)
FN_LOCAL_BOOL(lp_map_acl_inherit, bMap_acl_inherit)
FN_LOCAL_BOOL(lp_afs_share, bAfs_Share)
FN_LOCAL_BOOL(lp_acl_check_permissions, bAclCheckPermissions)
+FN_LOCAL_BOOL(lp_acl_group_control, bAclGroupControl)
FN_LOCAL_BOOL(lp_acl_map_full_control, bAclMapFullControl)
FN_LOCAL_INTEGER(lp_create_mask, iCreate_mask)
FN_LOCAL_INTEGER(lp_force_create_mode, iCreate_force_mode)
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 2052a98c02..a1855b0fa9 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -2237,10 +2237,42 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_
}
/****************************************************************************
+ Check if the current user group list contains a given group.
+****************************************************************************/
+
+static BOOL current_user_in_group(gid_t gid)
+{
+ int i;
+
+ for (i = 0; i < current_user.ngroups; i++) {
+ if (current_user.groups[i] == gid) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ Should we override a deny ?
+****************************************************************************/
+
+static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid)
+{
+ if ((errno == EACCES || errno == EPERM) &&
+ lp_acl_group_control(SNUM(conn)) &&
+ current_user_in_group(prim_gid)) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
+/****************************************************************************
Attempt to apply an ACL to a file or directory.
****************************************************************************/
-static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
+static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support)
{
connection_struct *conn = fsp->conn;
BOOL ret = False;
@@ -2305,7 +2337,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
i, strerror(errno) ));
- goto done;
+ goto fail;
}
if (p_ace->type == SMB_ACL_MASK) {
@@ -2331,7 +2363,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
i, strerror(errno) ));
- goto done;
+ goto fail;
}
/*
@@ -2343,7 +2375,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
i, strerror(errno) ));
- goto done;
+ goto fail;
}
}
@@ -2354,13 +2386,13 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
i, strerror(errno) ));
- goto done;
+ goto fail;
}
if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
(unsigned int)p_ace->perms, i, strerror(errno) ));
- goto done;
+ goto fail;
}
/*
@@ -2370,7 +2402,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
i, strerror(errno) ));
- goto done;
+ goto fail;
}
if( DEBUGLVL( 10 ))
@@ -2381,27 +2413,27 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
if (needs_mask && !got_mask_entry) {
if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
- goto done;
+ goto fail;
}
if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
- goto done;
+ goto fail;
}
if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
- goto done;
+ goto fail;
}
if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
- goto done;
+ goto fail;
}
if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
- goto done;
+ goto fail;
}
}
@@ -2413,7 +2445,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
strerror(errno) ));
- goto done;
+ goto fail;
}
/*
@@ -2430,10 +2462,26 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
*pacl_set_support = False;
}
- DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
- the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
- fsp->fsp_name, strerror(errno) ));
- goto done;
+ if (acl_group_override(conn, prim_gid)) {
+ int sret;
+
+ DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
+ unbecome_root();
+ if (sret == 0) {
+ ret = True;
+ }
+ }
+
+ if (ret == False) {
+ DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
+ the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
+ fsp->fsp_name, strerror(errno) ));
+ goto fail;
+ }
}
} else {
if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) {
@@ -2445,18 +2493,35 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
*pacl_set_support = False;
}
- DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
- fsp->fsp_name, strerror(errno) ));
- goto done;
+ if (acl_group_override(conn, prim_gid)) {
+ int sret;
+
+ DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl);
+ unbecome_root();
+ if (sret == 0) {
+ ret = True;
+ }
+ }
+
+ if (ret == False) {
+ DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
+ fsp->fsp_name, strerror(errno) ));
+ goto fail;
+ }
}
}
ret = True;
- done:
+ fail:
- if (the_acl != NULL)
- SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ if (the_acl != NULL) {
+ SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ }
return ret;
}
@@ -3127,7 +3192,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
*/
if (acl_perms && file_ace_list) {
- ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
+ ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
if (acl_set_support && ret == False) {
DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
free_canon_ace_list(file_ace_list);
@@ -3138,7 +3203,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
if (acl_perms && acl_set_support && fsp->is_directory) {
if (dir_ace_list) {
- if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
+ if (!set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support)) {
DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
free_canon_ace_list(file_ace_list);
free_canon_ace_list(dir_ace_list);
@@ -3151,17 +3216,32 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
*/
if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
- DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return False;
+ int sret = -1;
+
+ if (acl_group_override(conn, sbuf.st_gid)) {
+ DEBUG(5,("set_nt_acl: acl group control on and "
+ "current user in file %s primary group. Override delete_def_acl\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
+ unbecome_root();
+ }
+
+ if (sret == -1) {
+ DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
}
}
}
- if (acl_set_support)
+ if (acl_set_support) {
store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
(psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
+ }
/*
* If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
@@ -3184,11 +3264,24 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
fsp->fsp_name, (unsigned int)posix_perms ));
if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
- DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
+ int sret = -1;
+ if (acl_group_override(conn, sbuf.st_gid)) {
+ DEBUG(5,("set_nt_acl: acl group control on and "
+ "current user in file %s primary group. Override chmod\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
+ unbecome_root();
+ }
+
+ if (sret == -1) {
+ DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return False;
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
}
}
}