Mapping between POSIX and NT ACLs
Andreas Gruenbacher
agruen at suse.de
Mon Sep 9 14:44:32 GMT 2002
Hello,
here is an improved version of the patch.
--Andreas.
--- samba-2.2.5.orig/source/smbd/posix_acls.c 2002-06-19 03:13:48.000000000
+0200
+++ samba-2.2.5/source/smbd/posix_acls.c 2002-09-09 16:23:54.000000000 +0200
@@ -346,7 +346,23 @@
if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
nt_mask = UNIX_ACCESS_RWX;
} else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
+#ifdef OLD_MAPPING
+ /* Windows NT refuses to display ACEs with no permissions in them (but
+ they are perfectly legal with Windows 2000). If the ACE has empty
+ permissions we cannot use 0, so we map UNIX_ACCESS_NONE to WRITE_OWNER
+ which we ignore when set an ACL. */
nt_mask = UNIX_ACCESS_NONE;
+#else
+ /* With the new mapping it has become feasible to convert the entry to
+ DENY/.../FULL, which isn't so wrong anymore since we drop
+ ALLOW/Everone/NONE ACEs anyway. The only problem: This will mask off
+ permissions from the owner if he is member of the group with no
+ permissions. Perhaps it's better to fix the code that does that
+ masking off? */
+ *pacl_type = SEC_ACE_TYPE_ACCESS_DENIED;
+ nt_mask = UNIX_ACCESS_RWX | GENERIC_ALL_ACCESS;
+
+#endif
} else {
nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
@@ -678,6 +694,43 @@
return True;
}
+static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid,
DOM_SID *pfile_grp_sid)
+{
+ BOOL got_user_obj, got_group_obj;
+ canon_ace *current_ace;
+ int i, entries;
+
+ entries = count_canon_ace_list(ace);
+ got_user_obj = False;
+ got_group_obj = False;
+
+ for (i=0, current_ace = ace; i < entries; i++, current_ace =
current_ace->next) {
+ if (current_ace->type == SMB_ACL_USER_OBJ)
+ got_user_obj = True;
+ else if (current_ace->type == SMB_ACL_GROUP_OBJ)
+ got_group_obj = True;
+ }
+ if (got_user_obj && got_group_obj) {
+ print_canon_ace_list( "ACL had owning user/group entries", ace);
+ return;
+ } else {
+ print_canon_ace_list( "Faking owning user/group entries", ace);
+ }
+
+ for (i=0, current_ace = ace; i < entries; i++, current_ace =
current_ace->next) {
+ if (!got_user_obj && current_ace->owner_type == UID_ACE &&
+ sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
+ current_ace->type = SMB_ACL_USER_OBJ;
+ got_user_obj = True;
+ }
+ if (!got_group_obj && current_ace->owner_type == GID_ACE &&
+ sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+ got_group_obj = True;
+ }
+ }
+}
+
/****************************************************************************
Unpack a SEC_DESC into two canonical ace lists.
****************************************************************************/
@@ -688,6 +741,8 @@
canon_ace **ppfile_ace, canon_ace **ppdir_ace,
SEC_ACL *dacl)
{
+ extern DOM_SID global_sid_Creator_Owner;
+ extern DOM_SID global_sid_Creator_Group;
extern DOM_SID global_sid_World;
extern struct generic_mapping file_generic_mapping;
BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
@@ -805,15 +860,27 @@
/*
* Try and work out if the SID is a user or group
* as we need to flag these differently for POSIX.
+ * Note what kind of a POSIX ACL this should map to.
*/
if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
current_ace->owner_type = WORLD_ACE;
current_ace->unix_ug.world = -1;
+ current_ace->type = SMB_ACL_OTHER;
+ } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
+ current_ace->owner_type = UID_ACE;
+ current_ace->unix_ug.world = -1;
+ current_ace->type = SMB_ACL_USER_OBJ;
+ } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
+ current_ace->owner_type = GID_ACE;
+ current_ace->unix_ug.world = -1;
+ current_ace->type = SMB_ACL_GROUP_OBJ;
} else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid,
&sid_type)) {
current_ace->owner_type = UID_ACE;
+ current_ace->type = SMB_ACL_USER;
} else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid,
&sid_type)) {
current_ace->owner_type = GID_ACE;
+ current_ace->type = SMB_ACL_GROUP;
} else {
fstring str;
@@ -834,31 +901,6 @@
current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE
: DENY_ACE;
/*
- * Now note what kind of a POSIX ACL this should map to.
- */
-
- if(sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
-
- current_ace->type = SMB_ACL_USER_OBJ;
-
- } else if( sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
-
- current_ace->type = SMB_ACL_GROUP_OBJ;
-
- } else if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
-
- current_ace->type = SMB_ACL_OTHER;
-
- } else {
- /*
- * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
- * looking at owner_type.
- */
-
- current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER :
SMB_ACL_GROUP;
- }
-
- /*
* Now add the created ace to either the file list, the directory
* list, or both. We *MUST* preserve the order here (hence we use
* DLIST_ADD_END) as NT ACLs are order dependent.
@@ -971,6 +1013,14 @@
free_canon_ace_list(dir_ace);
file_ace = NULL;
dir_ace = NULL;
+ } else {
+ /*
+ * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
+ * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
+ * entries can be converted to *_OBJ.
+ */
+ check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
+ check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
}
*ppfile_ace = file_ace;
@@ -1399,11 +1449,10 @@
Note that this doesn't exactly match the NT semantics for an ACL. As POSIX
entries
are not ordered, and match on the most specific entry rather than walking a
list,
- then a simple POSIX permission of rw-r--r-- should really map to 6 entries,
+ then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
Entry 0: owner : deny all except read and write.
Entry 1: group : deny all except read.
- Entry 2: Everyone : deny all except read.
Entry 3: owner : allow read and write.
Entry 4: group : allow read.
Entry 5: Everyone : allow read.
@@ -1490,7 +1539,8 @@
switch(tagtype) {
case SMB_ACL_USER_OBJ:
/* Get the SID from the owner. */
- uid_to_sid( &sid, psbuf->st_uid );
+ /* uid_to_sid( &sid, psbuf->st_uid ); */
+ sid_copy(&sid, powner);
unix_ug.uid = psbuf->st_uid;
owner_type = UID_ACE;
break;
@@ -1509,7 +1559,8 @@
}
case SMB_ACL_GROUP_OBJ:
/* Get the SID from the owning group. */
- gid_to_sid( &sid, psbuf->st_gid );
+ /* gid_to_sid( &sid, psbuf->st_gid ); */
+ sid_copy(&sid, pgroup);
unix_ug.gid = psbuf->st_gid;
owner_type = GID_ACE;
break;
@@ -1882,6 +1933,8 @@
size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
{
+ extern DOM_SID global_sid_Creator_Owner;
+ extern DOM_SID global_sid_Creator_Group;
connection_struct *conn = fsp->conn;
SMB_STRUCT_STAT sbuf;
SEC_ACE *nt_ace_list = NULL;
@@ -1936,14 +1989,15 @@
posix_acl ? "present" : "absent",
dir_acl ? "present" : "absent" ));
- /*
- * Get the owner, group and world SIDs.
- */
+ /* Creator_Owner and Creator_Group should be used as owner and owning group
in the
+ Access ACL, but Windows NT/2000 seems to support them only for
inherit-only ACEs.
+ So we use the owner/owning group SID's instead. */
+ /* Get the owner, group and world SIDs. */
create_file_sids(&sbuf, &owner_sid, &group_sid);
/* Create the canon_ace lists. */
- file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid,
&group_sid);
+ file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid);
num_acls = count_canon_ace_list(file_ace);
/* We must have *some* ACLS. */
@@ -1953,6 +2007,7 @@
return 0;
}
+#if OLD_MAPPING
if (fsp->is_directory) {
/*
* If we have to fake a default ACL then this is the mode to use.
@@ -1962,6 +2017,15 @@
dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, &owner_sid, &group_sid);
num_dir_acls = count_canon_ace_list(dir_ace);
}
+#else
+ if (fsp->is_directory && dir_acl) {
+ sbuf.st_mode = 0;
+ /* dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, &owner_sid, &group_sid);
*/
+ dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
+ &global_sid_Creator_Owner, &global_sid_Creator_Group);
+ num_dir_acls = count_canon_ace_list(dir_ace);
+ }
+#endif
/* Allocate the ace list. */
if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)*
sizeof(SEC_ACE))) == NULL) {
@@ -1978,19 +2042,57 @@
{
canon_ace *ace;
int nt_acl_type;
+#ifndef OLD_MAPPING
+ mode_t other_perms;
+#endif
int i;
+#ifndef OLD_MAPPING
+ /* Find the SMB_ACL_OTHER entry: We will only remove entries with no
permissions
+ if the permissions for others are also zero. */
+ other_perms = 0;
+ for (ace = file_ace, i = 0; i < num_acls; i++, ace = ace->next) {
+ if (ace->type == SMB_ACL_OTHER) {
+ other_perms = ace->perms;
+ break;
+ }
+ }
+#endif
+
ace = file_ace;
for (i = 0; i < num_acls; i++, ace = ace->next) {
- SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
+ SEC_ACCESS acc;
+#ifndef OLD_MAPPING
+ if (!ace->perms && !other_perms)
+ continue;
+#endif
+ acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
0);
}
+#ifndef OLD_MAPPING
+ /* Find the SMB_ACL_OTHER entry: We will only remove entries with no
permissions
+ if the permissions for others are also zero. */
+ other_perms = 0;
+ for (ace = dir_ace, i = 0; i < num_dir_acls; i++, ace = ace->next) {
+ if (ace->type == SMB_ACL_OTHER) {
+ other_perms = ace->perms;
+ break;
+ }
+ }
+#endif
+
+
ace = dir_ace;
for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
- SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
+ SEC_ACCESS acc;
+#ifndef OLD_MAPPING
+ if (!ace->perms && !other_perms)
+ continue;
+#endif
+ acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
}
@@ -2015,6 +2117,18 @@
if(!*ppdesc) {
DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
sd_size = 0;
+#ifndef OLD_MAPPING
+ } else {
+ /* Windows 2000: The DACL_PROTECTED flag in the security
+ descriptor marks the ACL as non-inheriting, i.e., no
+ ACEs from higher level directories propagate to this
+ ACL. In the POSIX ACL model permissions are only
+ inherited at file create time, so ACLs never contain
+ any ACEs that are inherited dynamically. The DACL_PROTECTED
+ flag doesn't seem to bother Windows NT.
+ */
+ (*ppdesc)->type |= SE_DESC_DACL_PROTECTED;
+#endif
}
done:
More information about the samba-technical
mailing list