#include "trans2.h"
#include "passdb/lookup_sid.h"
#include "auth.h"
+#include "../librpc/gen_ndr/idmap.h"
extern const struct generic_mapping file_generic_mapping;
pace_other = pace;
}
+ if (setting_acl) {
+ /* Ensure when setting a POSIX ACL, that the uid for a
+ SMB_ACL_USER_OBJ ACE (the owner ACE entry) has a duplicate
+ permission entry as an SMB_ACL_USER, and a gid for a
+ SMB_ACL_GROUP_OBJ ACE (the primary group ACE entry) also has
+ a duplicate permission entry as an SMB_ACL_GROUP. If not,
+ then if the ownership or group ownership of this file or
+ directory gets changed, the user or group can lose their
+ access. */
+ bool got_duplicate_user = false;
+ bool got_duplicate_group = false;
+
+ for (pace = *pp_ace; pace; pace = pace->next) {
+ if (pace->type == SMB_ACL_USER &&
+ pace->unix_ug.uid == pace_user->unix_ug.uid) {
+ /* Already got one. */
+ got_duplicate_user = true;
+ } else if (pace->type == SMB_ACL_USER &&
+ pace->unix_ug.uid == pace_user->unix_ug.uid) {
+ /* Already got one. */
+ got_duplicate_group = true;
+ }
+ }
+
+ if (!got_duplicate_user) {
+ /* Add a duplicate SMB_ACL_USER entry. */
+ 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_USER;;
+ pace->owner_type = UID_ACE;
+ pace->unix_ug.uid = pace_user->unix_ug.uid;
+ pace->trustee = pace_user->trustee;
+ pace->attr = pace_user->attr;
+ pace->perms = pace_user->perms;
+
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_duplicate_group) {
+ /* Add a duplicate SMB_ACL_GROUP entry. */
+ 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);
+ }
+
+ }
+
return 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,("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)));
+ 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 (!dup_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);
+ } 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,("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)));
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("create_canon_ace_lists: 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.
****************************************************************************/
for(i = 0; i < dacl->num_aces; i++) {
struct security_ace *psa = &dacl->aces[i];
-
+ struct unixid unixid;
/*
* Create a canon_ace entry representing this NT DACL ACE.
*/
*/
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;
- }
-
- 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, ("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 (unixid.type == ID_TYPE_BOTH) {
+ 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;
+ }
+
+ /* 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 ((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)));
+ 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;
- }
-
- 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 (!dup_ace) {
- DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
- free_canon_ace_list(file_ace);
- free_canon_ace_list(dir_ace);
- 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) {