posix_acls.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,170 行 · 第 1/5 页

C
2,170
字号
			if (psa1->info.mask != psa2->info.mask)				continue;			if (!sid_equal(&psa1->trustee, &psa2->trustee))				continue;			/*			 * Ok - permission bits and SIDs are equal.			 * Check if flags were re-written.			 */			if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {				psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));				psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);							} else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {				psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));				psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);							}		}	}	for(i = 0; i < dacl->num_aces; i++) {		SEC_ACE *psa = &dacl->ace[i];		/*		 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).		 */		if (non_mappable_sid(&psa->trustee)) {			fstring str;			DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",				sid_to_string(str, &psa->trustee) ));			continue;		}		/*		 * Create a cannon_ace entry representing this NT DACL ACE.		 */		if ((current_ace = SMB_MALLOC_P(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;		}		ZERO_STRUCTP(current_ace);		sid_copy(&current_ace->trustee, &psa->trustee);		/*		 * 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(&current_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(&current_ace->trustee, &global_sid_Creator_Owner)) {			current_ace->owner_type = UID_ACE;			current_ace->unix_ug.uid = pst->st_uid;			current_ace->type = SMB_ACL_USER_OBJ;			/*			 * The Creator Owner entry only specifies inheritable permissions,			 * never access permissions. WinNT doesn't always set the ACE to			 *INHERIT_ONLY, though.			 */			if (nt4_compatible_acls())				psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;		} else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {			current_ace->owner_type = GID_ACE;			current_ace->unix_ug.gid = pst->st_gid;			current_ace->type = SMB_ACL_GROUP_OBJ;			/*			 * The Creator Group entry only specifies inheritable permissions,			 * never access permissions. WinNT doesn't always set the ACE to			 *INHERIT_ONLY, though.			 */			if (nt4_compatible_acls())				psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;		} else if (NT_STATUS_IS_OK(sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid))) {			current_ace->owner_type = UID_ACE;			current_ace->type = SMB_ACL_USER;		} else if (NT_STATUS_IS_OK(sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid))) {			current_ace->owner_type = GID_ACE;			current_ace->type = SMB_ACL_GROUP;		} else {			fstring str;			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_to_string(str, &current_ace->trustee) ));			SAFE_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->info, S_IRUSR);		current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;		current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);		/*		 * 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)) {				DLIST_ADD_END(dir_ace, current_ace, tmp_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->fsp_name ));					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 (!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;				} else {					/*					 * We must not free current_ace here as its					 * pointer is now owned by the dir_ace list.					 */					current_ace = NULL;				}			}		}		/*		 * Only add to the file ACL if not inherit only.		 */		if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {			DLIST_ADD_END(file_ace, current_ace, tmp_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->fsp_name ));				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);			}			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.		 */		SAFE_FREE(current_ace);	}	if (fsp->is_directory && all_aces_are_inherit_only) {		/*		 * Windows 2000 is doing one of these weird 'inherit acl'		 * traverses to conserve NTFS ACL resources. Just pretend		 * there was no DACL sent. JRA.		 */		DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));		free_canon_ace_list(file_ace);		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. Usually we will already have these		 * entries in the Default ACL, and the Access ACL will not have them.		 */		if (file_ace) {			check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);		}		if (dir_ace) {			check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);		}	}	*ppfile_ace = file_ace;	*ppdir_ace = dir_ace;	return True;}/**************************************************************************** ASCII art time again... JRA :-). We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly, we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW entries). Secondly, the merge code has ensured that all duplicate SID entries for allow or deny have been merged, so the same SID can only appear once in the deny list or once in the allow list. We then process as follows : --------------------------------------------------------------------------- First pass - look for a Everyone DENY entry. If it is deny all (rwx) trunate the list at this point. Else, walk the list from this point and use the deny permissions of this entry as a mask on all following allow entries. Finally, delete the Everyone DENY entry (we have applied it to everything possible). In addition, in this pass we remove any DENY entries that have  no permissions (ie. they are a DENY nothing). --------------------------------------------------------------------------- Second pass - only deal with deny user entries. DENY user1 (perms XXX) new_perms = 0 for all following allow group entries where user1 is in group	new_perms |= group_perms; user1 entry perms = new_perms & ~ XXX; Convert the deny entry to an allow entry with the new perms and push to the end of the list. Note if the user was in no groups this maps to a specific allow nothing entry for this user. The common case from the NT ACL choser (userX deny all) is optimised so we don't do the group lookup - we just map to an allow nothing entry. What we're doing here is inferring the allow permissions the person setting the ACE on user1 wanted by looking at the allow permissions on the groups the user is currently in. This will be a snapshot, depending on group membership but is the best we can do and has the advantage of failing closed rather than open. --------------------------------------------------------------------------- Third pass - only deal with deny group entries. DENY group1 (perms XXX) for all following allow user entries where user is in group1   user entry perms = user entry perms & ~ XXX; If there is a group Everyone allow entry with permissions YYY, convert the group1 entry to an allow entry and modify its permissions to be : new_perms = YYY & ~ XXX and push to the end of the list. If there is no group Everyone allow entry then convert the group1 entry to a allow nothing entry and push to the end of the list. Note that the common case from the NT ACL choser (groupX deny all) cannot be optimised here as we need to modify user entries who are in the group to change them to a deny all also. What we're doing here is modifying the allow permissions of user entries (which are more specific in POSIX ACLs) to mask out the explicit deny set on the group they are in. This will be a snapshot depending on current group membership but is the best we can do and has the advantage of failing closed rather than open. --------------------------------------------------------------------------- Fourth pass - cope with cumulative permissions. for all allow user entries, if there exists an allow group entry with more permissive permissions, and the user is in that group, rewrite the allow user permissions to contain both sets of permissions. Currently the code for this is #ifdef'ed out as these semantics make no sense to me. JRA. --------------------------------------------------------------------------- Note we *MUST* do the deny user pass first as this will convert deny user entries into allow user entries which can then be processed by the deny group pass. The above algorithm took a *lot* of thinking about - hence this explaination :-). JRA.****************************************************************************//**************************************************************************** Process a canon_ace list entries. This is very complex code. We need to go through and remove the "deny" permissions from any allow entry that matches the id of this entry. We have already refused any NT ACL that wasn't in correct order (DENY followed by ALLOW). If any allow entry ends up with zero permissions, we just remove it (to fail safe). We have already removed any duplicate ace entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all allow entries.****************************************************************************/static void process_deny_list( canon_ace **pp_ace_list ){	canon_ace *ace_list = *pp_ace_list;	canon_ace *curr_ace = NULL;	canon_ace *curr_ace_next = NULL;	/* Pass 1 above - look for an Everyone, deny entry. */	for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {		canon_ace *allow_ace_p;		curr_ace_next = curr_ace->next; /* So we can't lose the link. */		if (curr_ace->attr != DENY_ACE)			continue;		if (curr_ace->perms == (mode_t)0) {			/* Deny nothing entry - delete. */			DLIST_REMOVE(ace_list, curr_ace);			continue;		}		if (!sid_equal(&curr_ace->trustee, &global_sid_World))			continue;		/* JRATEST - assert. */		SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);		if (curr_ace->perms == ALL_ACE_PERMS) {			/*			 * Optimisation. This is a DENY_ALL to Everyone. Truncate the			 * list at this point including this entry.			 */			canon_ace *prev_entry = curr_ace->prev;			free_canon_ace_list( curr_ace );			if (prev_entry)				prev_entry->next = NULL;			else {				/* We deleted the entire list. */				ace_list = NULL;			}			break;		}		for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {			/* 			 * Only mask off allow entries.			 */			if (allow_ace_p->attr != ALLOW_ACE)				continue;			allow_ace_p->perms &= ~curr_ace->perms;		}		/*		 * Now it's been applied, remove it.		 */		DLIST_REMOVE(ace_list, curr_ace);	}	/* Pass 2 above - deal with deny user entries. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?