#include "trans2.h"
#include "passdb/lookup_sid.h"
#include "auth.h"
+#include "../librpc/gen_ndr/idmap.h"
+#include "lib/param/loadparm.h"
extern const struct generic_mapping file_generic_mapping;
pace->unix_ug.gid == pace_user->unix_ug.gid) {
/* Already got one. */
got_duplicate_group = true;
+ } else if ((pace->type == SMB_ACL_GROUP)
+ && (dom_sid_equal(&pace->trustee, &pace_user->trustee))) {
+ /* If the SID owning the file appears
+ * in a group entry, then we have
+ * enough duplication, they will still
+ * have access */
+ got_duplicate_user = true;
}
}
+ /* If the SID is equal for the user and group that we need
+ to add the duplicate for, add only the group */
+ if (!got_duplicate_user && !got_duplicate_group
+ && dom_sid_equal(&pace_group->trustee,
+ &pace_user->trustee)) {
+ /* Add a duplicate SMB_ACL_GROUP entry, this
+ * will cover the owning SID as well, as it
+ * will always be mapped to both a uid and
+ * gid. */
+
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("ensure_canon_entry_valid: talloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_GROUP;;
+ pace->owner_type = GID_ACE;
+ pace->unix_ug.gid = pace_group->unix_ug.gid;
+ pace->trustee = pace_group->trustee;
+ pace->attr = pace_group->attr;
+ pace->perms = pace_group->perms;
+
+ DLIST_ADD(*pp_ace, pace);
+
+ /* We're done here, make sure the
+ statements below are not executed. */
+ got_duplicate_user = true;
+ got_duplicate_group = true;
+ }
+
if (!got_duplicate_user) {
/* Add a duplicate SMB_ACL_USER entry. */
if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
pace->perms = pace_user->perms;
DLIST_ADD(*pp_ace, pace);
+
+ got_duplicate_user = true;
}
if (!got_duplicate_group) {
pace->perms = pace_group->perms;
DLIST_ADD(*pp_ace, pace);
+
+ got_duplicate_group = true;
}
}
DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
}
+static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
+ canon_ace **file_ace, canon_ace **dir_ace,
+ bool *got_file_allow, bool *got_dir_allow,
+ bool *all_aces_are_inherit_only,
+ canon_ace *current_ace)
+{
+
+ /*
+ * Map the given NT permissions into a UNIX mode_t containing only
+ * S_I(R|W|X)USR bits.
+ */
+
+ current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
+ current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
+
+ /* Store the ace_flag. */
+ current_ace->ace_flags = psa->flags;
+
+ /*
+ * 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.
+ */
+
+ if (fsp->is_directory) {
+
+ /*
+ * We can only add to the default POSIX ACE list if the ACE is
+ * designed to be inherited by both files and directories.
+ */
+
+ if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
+ (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+ canon_ace *current_dir_ace = current_ace;
+ DLIST_ADD_END(*dir_ace, current_ace, canon_ace *);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ *got_dir_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && *got_dir_allow) {
+ DEBUG(0,("add_current_ace_to_acl: "
+ "malformed ACL in "
+ "inheritable ACL! Deny entry "
+ "after Allow entry. Failing "
+ "to set on file %s.\n",
+ fsp_str_dbg(fsp)));
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("add_current_ace_to_acl: adding dir ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+
+ /*
+ * If this is not an inherit only ACE we need to add a duplicate
+ * to the file acl.
+ */
+
+ if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ canon_ace *dup_ace = dup_canon_ace(current_ace);
+
+ if (!dup_ace) {
+ DEBUG(0,("add_current_ace_to_acl: malloc fail !\n"));
+ return False;
+ }
+
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the dir_ace list.
+ */
+ current_ace = dup_ace;
+ /* We've essentially split this ace into two,
+ * and added the ace with inheritance request
+ * bits to the directory ACL. Drop those bits for
+ * the ACE we're adding to the file list. */
+ current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY);
+ } else {
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the dir_ace list.
+ */
+ current_ace = NULL;
+ }
+
+ /*
+ * current_ace is now either owned by file_ace
+ * or is NULL. We can safely operate on current_dir_ace
+ * to treat mapping for default acl entries differently
+ * than access acl entries.
+ */
+
+ if (current_dir_ace->owner_type == UID_ACE) {
+ /*
+ * We already decided above this is a uid,
+ * for default acls ace's only CREATOR_OWNER
+ * maps to ACL_USER_OBJ. All other uid
+ * ace's are ACL_USER.
+ */
+ if (dom_sid_equal(¤t_dir_ace->trustee,
+ &global_sid_Creator_Owner)) {
+ current_dir_ace->type = SMB_ACL_USER_OBJ;
+ } else {
+ current_dir_ace->type = SMB_ACL_USER;
+ }
+ }
+
+ if (current_dir_ace->owner_type == GID_ACE) {
+ /*
+ * We already decided above this is a gid,
+ * for default acls ace's only CREATOR_GROUP
+ * maps to ACL_GROUP_OBJ. All other uid
+ * ace's are ACL_GROUP.
+ */
+ if (dom_sid_equal(¤t_dir_ace->trustee,
+ &global_sid_Creator_Group)) {
+ current_dir_ace->type = SMB_ACL_GROUP_OBJ;
+ } else {
+ current_dir_ace->type = SMB_ACL_GROUP;
+ }
+ }
+ }
+ }
+
+ /*
+ * Only add to the file ACL if not inherit only.
+ */
+
+ if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ DLIST_ADD_END(*file_ace, current_ace, canon_ace *);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ *got_file_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && got_file_allow) {
+ DEBUG(0,("add_current_ace_to_acl: malformed "
+ "ACL in file ACL ! Deny entry after "
+ "Allow entry. Failing to set on file "
+ "%s.\n", fsp_str_dbg(fsp)));
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("add_current_ace_to_acl: adding file ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+ *all_aces_are_inherit_only = False;
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the file_ace list.
+ */
+ current_ace = NULL;
+ }
+
+ /*
+ * Free if ACE was not added.
+ */
+
+ TALLOC_FREE(current_ace);
+ return true;
+}
+
/****************************************************************************
Unpack a struct security_descriptor into two canonical ace lists.
****************************************************************************/
*/
psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
- } else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid)) {
- current_ace->owner_type = UID_ACE;
- /* If it's the owning user, this is a user_obj, not
- * a user. */
- if (current_ace->unix_ug.uid == pst->st_ex_uid) {
- current_ace->type = SMB_ACL_USER_OBJ;
- } else {
- current_ace->type = SMB_ACL_USER;
- }
- } else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid)) {
- current_ace->owner_type = GID_ACE;
- /* If it's the primary group, this is a group_obj, not
- * a group. */
- if (current_ace->unix_ug.gid == pst->st_ex_gid) {
- current_ace->type = SMB_ACL_GROUP_OBJ;
- } else {
- current_ace->type = SMB_ACL_GROUP;
- }
} else {
- /*
- * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
- */
-
- if (non_mappable_sid(&psa->trustee)) {
- DEBUG(10, ("create_canon_ace_lists: ignoring "
- "non-mappable SID %s\n",
- sid_string_dbg(&psa->trustee)));
- TALLOC_FREE(current_ace);
- continue;
- }
+ struct unixid unixid;
- if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
- DEBUG(10, ("create_canon_ace_lists: ignoring "
- "unknown or foreign SID %s\n",
- sid_string_dbg(&psa->trustee)));
+ if (!sids_to_unixids(¤t_ace->trustee, 1, &unixid)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
TALLOC_FREE(current_ace);
- continue;
+ DEBUG(0, ("create_canon_ace_lists: sids_to_unixids "
+ "failed for %s (allocation failure)\n",
+ sid_string_dbg(¤t_ace->trustee)));
+ return false;
}
- free_canon_ace_list(file_ace);
- free_canon_ace_list(dir_ace);
- DEBUG(0, ("create_canon_ace_lists: unable to map SID "
- "%s to uid or gid.\n",
- sid_string_dbg(¤t_ace->trustee)));
- TALLOC_FREE(current_ace);
- return False;
- }
-
- /*
- * Map the given NT permissions into a UNIX mode_t containing only
- * S_I(R|W|X)USR bits.
- */
-
- current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
- current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
-
- /* Store the ace_flag. */
- current_ace->ace_flags = psa->flags;
-
- /*
- * 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.
- */
-
- if (fsp->is_directory) {
-
- /*
- * We can only add to the default POSIX ACE list if the ACE is
- * designed to be inherited by both files and directories.
- */
-
- if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
- (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
-
- canon_ace *current_dir_ace = current_ace;
- DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
-
- /*
- * Note if this was an allow ace. We can't process
- * any further deny ace's after this.
- */
-
- if (current_ace->attr == ALLOW_ACE)
- got_dir_allow = True;
-
- if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
- DEBUG(0,("create_canon_ace_lists: "
- "malformed ACL in "
- "inheritable ACL! Deny entry "
- "after Allow entry. Failing "
- "to set on file %s.\n",
- fsp_str_dbg(fsp)));
- free_canon_ace_list(file_ace);
- free_canon_ace_list(dir_ace);
- return False;
- }
-
- if( DEBUGLVL( 10 )) {
- dbgtext("create_canon_ace_lists: adding dir ACL:\n");
- print_canon_ace( current_ace, 0);
- }
-
- /*
- * If this is not an inherit only ACE we need to add a duplicate
- * to the file acl.
- */
-
- if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
- canon_ace *dup_ace = dup_canon_ace(current_ace);
+ if (unixid.type == ID_TYPE_BOTH) {
+ /* If it's the owning user, this is a
+ * user_obj, not a user. This way, we
+ * get a valid ACL for groups that own
+ * files, without putting user ACL
+ * entries in for groups otherwise */
+ if (unixid.id == pst->st_ex_uid) {
+ current_ace->owner_type = UID_ACE;
+ current_ace->unix_ug.uid = unixid.id;
+ current_ace->type = SMB_ACL_USER_OBJ;
+
+ /* Add the user object to the posix ACL,
+ and proceed to the group mapping
+ below. This handles the talloc_free
+ of current_ace if not added for some
+ reason */
+ if (!add_current_ace_to_acl(fsp,
+ psa,
+ &file_ace,
+ &dir_ace,
+ &got_file_allow,
+ &got_dir_allow,
+ &all_aces_are_inherit_only,
+ current_ace)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return false;
+ }
- if (!dup_ace) {
- DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+ if ((current_ace = talloc(talloc_tos(),
+ canon_ace)) == NULL) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
+ DEBUG(0,("create_canon_ace_lists: "
+ "malloc fail.\n"));
return False;
}
- /*
- * We must not free current_ace here as its
- * pointer is now owned by the dir_ace list.
- */
- current_ace = dup_ace;
- /* We've essentially split this ace into two,
- * and added the ace with inheritance request
- * bits to the directory ACL. Drop those bits for
- * the ACE we're adding to the file list. */
- current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
- SEC_ACE_FLAG_CONTAINER_INHERIT|
- SEC_ACE_FLAG_INHERIT_ONLY);
+ ZERO_STRUCTP(current_ace);
+ }
+
+ sid_copy(¤t_ace->trustee, &psa->trustee);
+
+ current_ace->unix_ug.gid = unixid.id;
+ current_ace->owner_type = GID_ACE;
+ /* If it's the primary group, this is a
+ group_obj, not a group. */
+ if (current_ace->unix_ug.gid == pst->st_ex_gid) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
} else {
- /*
- * We must not free current_ace here as its
- * pointer is now owned by the dir_ace list.
- */
- current_ace = NULL;
+ current_ace->type = SMB_ACL_GROUP;
}
+ } else if (unixid.type == ID_TYPE_UID) {
+ current_ace->owner_type = UID_ACE;
+ current_ace->unix_ug.uid = unixid.id;
+ /* If it's the owning user, this is a user_obj,
+ not a user. */
+ if (current_ace->unix_ug.uid == pst->st_ex_uid) {
+ current_ace->type = SMB_ACL_USER_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_USER;
+ }
+ } else if (unixid.type == ID_TYPE_GID) {
+ current_ace->unix_ug.gid = unixid.id;
+ current_ace->owner_type = GID_ACE;
+ /* If it's the primary group, this is a
+ group_obj, not a group. */
+ if (current_ace->unix_ug.gid == pst->st_ex_gid) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_GROUP;
+ }
+ } else {
/*
- * current_ace is now either owned by file_ace
- * or is NULL. We can safely operate on current_dir_ace
- * to treat mapping for default acl entries differently
- * than access acl entries.
+ * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
*/
- if (current_dir_ace->owner_type == UID_ACE) {
- /*
- * We already decided above this is a uid,
- * for default acls ace's only CREATOR_OWNER
- * maps to ACL_USER_OBJ. All other uid
- * ace's are ACL_USER.
- */
- if (dom_sid_equal(¤t_dir_ace->trustee,
- &global_sid_Creator_Owner)) {
- current_dir_ace->type = SMB_ACL_USER_OBJ;
- } else {
- current_dir_ace->type = SMB_ACL_USER;
- }
+ if (non_mappable_sid(&psa->trustee)) {
+ DEBUG(10, ("create_canon_ace_lists: ignoring "
+ "non-mappable SID %s\n",
+ sid_string_dbg(&psa->trustee)));
+ TALLOC_FREE(current_ace);
+ continue;
}
- if (current_dir_ace->owner_type == GID_ACE) {
- /*
- * We already decided above this is a gid,
- * for default acls ace's only CREATOR_GROUP
- * maps to ACL_GROUP_OBJ. All other uid
- * ace's are ACL_GROUP.
- */
- if (dom_sid_equal(¤t_dir_ace->trustee,
- &global_sid_Creator_Group)) {
- current_dir_ace->type = SMB_ACL_GROUP_OBJ;
- } else {
- current_dir_ace->type = SMB_ACL_GROUP;
- }
+ if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
+ DEBUG(10, ("create_canon_ace_lists: ignoring "
+ "unknown or foreign SID %s\n",
+ sid_string_dbg(&psa->trustee)));
+ TALLOC_FREE(current_ace);
+ continue;
}
- }
- }
-
- /*
- * Only add to the file ACL if not inherit only.
- */
- if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
- DLIST_ADD_END(file_ace, current_ace, canon_ace *);
-
- /*
- * Note if this was an allow ace. We can't process
- * any further deny ace's after this.
- */
-
- if (current_ace->attr == ALLOW_ACE)
- got_file_allow = True;
-
- if ((current_ace->attr == DENY_ACE) && got_file_allow) {
- DEBUG(0,("create_canon_ace_lists: malformed "
- "ACL in file ACL ! Deny entry after "
- "Allow entry. Failing to set on file "
- "%s.\n", fsp_str_dbg(fsp)));
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
- return False;
- }
-
- if( DEBUGLVL( 10 )) {
- dbgtext("create_canon_ace_lists: adding file ACL:\n");
- print_canon_ace( current_ace, 0);
+ DEBUG(0, ("create_canon_ace_lists: unable to map SID "
+ "%s to uid or gid.\n",
+ sid_string_dbg(¤t_ace->trustee)));
+ TALLOC_FREE(current_ace);
+ return false;
}
- all_aces_are_inherit_only = False;
- /*
- * We must not free current_ace here as its
- * pointer is now owned by the file_ace list.
- */
- current_ace = NULL;
}
- /*
- * Free if ACE was not added.
- */
-
- TALLOC_FREE(current_ace);
+ /* handles the talloc_free of current_ace if not added for some reason */
+ if (!add_current_ace_to_acl(fsp, psa, &file_ace, &dir_ace,
+ &got_file_allow, &got_dir_allow,
+ &all_aces_are_inherit_only, current_ace)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return false;
+ }
}
if (fsp->is_directory && all_aces_are_inherit_only) {
ZERO_STRUCT( finfo );
ZERO_STRUCT( fh );
- finfo.fnum = -1;
+ finfo.fnum = FNUM_FIELD_INVALID;
finfo.conn = conn;
finfo.fh = &fh;
finfo.fh->fd = -1;