summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/posix_acls.c220
1 files changed, 198 insertions, 22 deletions
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 54b45529d0..73f7326e6a 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -23,6 +23,13 @@
#include "includes.h"
+typedef struct canon_ace {
+ struct canon_ace *next, *prev;
+ acl_tag_t type;
+ acl_perm_t perms;
+ DOM_SID sid;
+} canon_ace;
+
/****************************************************************************
Function to create owner and group SIDs from a SMB_STRUCT_STAT.
****************************************************************************/
@@ -323,29 +330,167 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p
}
/****************************************************************************
+ Create a linked list of canonical ACE entries. This is sorted so that DENY
+ entries are at the front of the list, as NT requires.
+****************************************************************************/
+
+canon_ace *canonicalise_acl( acl_t posix_acl, SMB_STRUCT_STAT *psbuf)
+{
+ extern DOM_SID global_sid_World;
+ acl_permset_t acl_mask = (ACL_READ|ACL_WRITE|ACL_EXECUTE);
+ canon_ace *list_head = NULL;
+ canon_ace *ace = NULL;
+ canon_ace *next_ace = NULL;
+ int entry_id = ACL_FIRST_ENTRY;
+
+ if (posix_acl == NULL)
+ return default_canonicalise_acl(psbuf);
+
+ while ( acl_get_entry(posix_acl, entry_id, &entry) == 1) {
+ acl_tag_t tagtype;
+ acl_permset_t permset;
+ DOM_SID sid;
+
+ /* get_next... */
+ if (entry_id == ACL_FIRST_ENTRY)
+ entry_id = ACL_NEXT_ENTRY;
+
+ /* Is this a MASK entry ? */
+ if (acl_get_tag_type(entry, &tagtype) == -1)
+ continue;
+
+ if (acl_get_permset(entry, &permset) == -1)
+ continue;
+
+ /* Decide which SID to use based on the ACL type. */
+ switch(tagtype) {
+ ACL_USER_OBJ:
+ /* Get the SID from the owner. */
+ uid_to_sid( &sid, psbuf->st_uid );
+ break;
+ ACL_USER:
+ {
+ uid_t *puid = (uid_t *)acl_get_qualifier(entry);
+ if (puid == NULL) {
+ DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
+ continue;
+ }
+ uid_to_sid( &sid, *puid);
+ break;
+ }
+ ACL_GROUP_OBJ:
+ /* Get the SID from the owning group. */
+ gid_to_sid( &sid, psbuf->st_gid );
+ break;
+ ACL_GROUP:
+ {
+ gid_t *pgid = (gid_t *)acl_get_qualifier(entry);
+ if (pgid == NULL) {
+ DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
+ continue;
+ }
+ gid_to_sid( &sid, *pgid);
+ break;
+ }
+ ACL_MASK:
+ acl_mask = permset;
+ continue; /* Don't count the mask as an entry. */
+ ACL_OTHER_OBJ:
+ /* Use the Everyone SID */
+ sid = global_sid_World;
+ break;
+ default:
+ DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
+ continue;
+ }
+
+ /*
+ * Add this entry to the list.
+ */
+
+ if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
+ goto fail;
+
+ ZERO_STRUCTP(ace);
+ ace->type = tagtype;
+ ace->perms = permset;
+ ace->sid = sid;
+
+ DLIST_ADD(list_head, ace);
+ }
+
+ /*
+ * Now go through the list, masking the permissions with the
+ * acl_mask. If the permissions are 0 and the type is ACL_USER
+ * or ACL_GROUP then it's a DENY entry and should be listed
+ * first. If the permissions are 0 and the type is ACL_USER_OBJ,
+ * ACL_GROUP_OBJ or ACL_OTHER_OBJ then remove the entry as they
+ * can never apply.
+ */
+
+ for ( ace = list_head; ace; ace = next_ace) {
+ next_ace = ace_next;
+ ace->perms &= acl_mask;
+
+ if (ace->perms == 0) {
+ switch (ace->type) {
+ ACL_USER_OBJ:
+ ACL_GROUP_OBJ:
+ ACL_OTHER_OBJ:
+ DLIST_REMOVE(list_head, ace);
+ break;
+ ACL_USER:
+ ACL_GROUP:
+ DLIST_PROMOTE(list_head, ace);
+ break;
+ }
+ }
+ }
+
+ return list_head;
+}
+
+/****************************************************************************
Go through the ACL entries one by one, count them and extract the permset
of the mask entry as we scan the acl.
****************************************************************************/
-static size_t get_num_posix_entries(acl_t posix_acl, acl_permset_t *posix_mask)
+static size_t get_num_entries(acl_t posix_acl, acl_permset_t *file_mask)
{
size_t num_entries;
acl_entry_t entry;
int entry_id = ACL_FIRST_ENTRY;
- *posix_mask = (ACL_READ|ACL_WRITE|ACL_EXECUTE);
+ *file_mask = (ACL_READ|ACL_WRITE|ACL_EXECUTE);
+
+ /*
+ * If the acl is NULL, then return 3 as we will fake this using UNIX
+ * permissions.
+ */
- for( num_entries = 0; acl_get_entry(posix_acl, entry_id, &entry) != -1; num_entries++) {
+ if (posix_acl == NULL)
+ return 3;
+
+ num_entries = 0;
+ while ( acl_get_entry(posix_acl, entry_id, &entry) == 1) {
acl_tag_t tagtype;
acl_permset_t permset;
- entry_id = ACL_NEXT_ENTRY;
+ /* get_next... */
+ if (entry_id == ACL_FIRST_ENTRY)
+ entry_id = ACL_NEXT_ENTRY;
+
+ /* Is this a MASK entry ? */
if (acl_get_tag_type(entry, &tagtype) == -1)
continue;
- if (tagtype == ACL_MASK)
+ if (tagtype == ACL_MASK) {
if (acl_get_permset(entry, &permset) == 0)
- *posix_mask = permset;
+ *file_mask = permset;
+ continue; /* Don't count the mask as an entry. */
+ }
+
+ num_entries++;
}
return num_entries;
@@ -375,12 +520,17 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
int other_acl_type;
size_t num_acls = 0;
size_t num_dir_acls = 0;
+ size _t i;
acl_t posix_acl = NULL;
acl_t directory_acl = NULL;
+ acl_permset_t file_mask = 0;
+ acl_permset_t directory_mask = 0;
*ppdesc = NULL;
if(fsp->is_directory || fsp->fd == -1) {
+
+ /* Get the stat struct for the owner info. */
if(vfs_stat(fsp,fsp->fsp_name, &sbuf) != 0) {
return 0;
}
@@ -388,25 +538,25 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
* Get the ACL from the path.
*/
- if ((posix_acl = acl_get_file( dos_to_unix(fsp->fsp_name, False), ACL_TYPE_ACCESS)) == NULL)
- return 0;
+ posix_acl = acl_get_file( dos_to_unix(fsp->fsp_name, False), ACL_TYPE_ACCESS);
/*
* If it's a directory get the default POSIX ACL.
*/
- if(fsp->is_directory) {
- }
+ if(fsp->is_directory)
+ directory_acl = acl_get_file( dos_to_unix(fsp->fsp_name, False), ACL_TYPE_DEFAULT);
} else {
+
+ /* Get the stat struct for the owner info. */
if(fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
return 0;
}
/*
* Get the ACL from the fd.
*/
- if ((posix_acl = acl_get_fd( fsp->fd)) == NULL)
- return 0;
+ posix_acl = acl_get_fd(fsp->fd);
}
/*
@@ -420,18 +570,44 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
* the mask.
*/
- num_posix_entries = get_num_posix_entries(posix_acl, &posix_mask);
+ num_acls = get_num_entries(posix_acl, &file_mask);
+ if (fsp->is_directory)
+ num_dir_acls = get_num_entries(directory_acl, &directory_mask);
- /*
- * Create the generic 3 element UNIX acl.
- */
+ /* Allocate the ace list. */
+ if ((ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
+ goto fail:
+ }
+
+ memset(ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
+
+ for (i = 0; i < num_acls; i++) {
+ SEC_ACCESS acc = map_unix_perms();
+ }
+
+ for (i = 0; i < num_dir_acls; i++) {
+ SEC_ACCESS acc = map_unix_perms();
+ }
+
+ done:
+
+ if (posix_acl)
+ acl_free(posix_acl);
+ if (directory_acl)
+ acl_free(directory_acl);
+
+ } else {
+
+ /*
+ * Fall back to the generic 3 element UNIX permissions.
+ */
- owner_access = map_unix_perms(&owner_acl_type, sbuf.st_mode,
- S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
- group_access = map_unix_perms(&grp_acl_type, sbuf.st_mode,
- S_IRGRP, S_IWGRP, S_IXGRP, fsp->is_directory);
- other_access = map_unix_perms(&other_acl_type, sbuf.st_mode,
- S_IROTH, S_IWOTH, S_IXOTH, fsp->is_directory);
+ owner_access = map_unix_perms(&owner_acl_type, sbuf.st_mode,
+ S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory);
+ group_access = map_unix_perms(&grp_acl_type, sbuf.st_mode,
+ S_IRGRP, S_IWGRP, S_IXGRP, fsp->is_directory);
+ other_access = map_unix_perms(&other_acl_type, sbuf.st_mode,
+ S_IROTH, S_IWOTH, S_IXOTH, fsp->is_directory);
if(owner_access.mask)
init_sec_ace(&ace_list[num_acls++], &owner_sid, owner_acl_type, owner_access, 0);