Author: ekohl Date: Tue Nov 26 16:56:33 2013 New Revision: 61103 URL: http://svn.reactos.org/svn/reactos?rev=61103&view=rev Log: [NETAPI32] BuildUserInfoBuffer: Set the UF_PASSWD_CANT_CHANGE account control flag if the user does not have the USER_CHANGE_PASSWORD access right for his own account data.
Modified: trunk/reactos/dll/win32/netapi32/user.c Modified: trunk/reactos/dll/win32/netapi32/user.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/netapi32/user.c?rev=61103&r1=61102&r2=61103&view=diff ============================================================================== --- trunk/reactos/dll/win32/netapi32/user.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/netapi32/user.c [iso-8859-1] Tue Nov 26 16:56:33 2013 @@ -66,10 +66,76 @@ static +NTSTATUS +GetAllowedWorldAce(IN PACL Acl, + OUT PACCESS_ALLOWED_ACE *Ace) +{ + SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; + ULONG WorldSid[sizeof(SID) / sizeof(ULONG) + SID_MAX_SUB_AUTHORITIES]; + ACL_SIZE_INFORMATION AclSize; + PVOID LocalAce = NULL; + ULONG i; + NTSTATUS Status; + + *Ace = NULL; + + RtlInitializeSid((PSID)WorldSid, + &WorldAuthority, + 1); + *(RtlSubAuthoritySid((PSID)WorldSid, 0)) = SECURITY_WORLD_RID; + + Status = RtlQueryInformationAcl(Acl, + &AclSize, + sizeof(AclSize), + AclSizeInformation); + if (!NT_SUCCESS(Status)) + return Status; + + for (i = 0; i < AclSize.AceCount; i++) + { + Status = RtlGetAce(Acl, i, &LocalAce); + if (!NT_SUCCESS(Status)) + return Status; + + if (((PACE_HEADER)LocalAce)->AceType != ACCESS_ALLOWED_ACE_TYPE) + continue; + + if (RtlEqualSid((PSID)WorldSid, + (PSID)&((PACCESS_ALLOWED_ACE)LocalAce)->SidStart)) + { + *Ace = (PACCESS_ALLOWED_ACE)LocalAce; + return STATUS_SUCCESS; + } + } + + return STATUS_SUCCESS; +} + + +static ULONG -GetAccountFlags(ULONG AccountControl) +GetAccountFlags(ULONG AccountControl, + PACL Dacl) { + PACCESS_ALLOWED_ACE Ace = NULL; ULONG Flags = UF_SCRIPT; + NTSTATUS Status; + + if (Dacl != NULL) + { + Status = GetAllowedWorldAce(Dacl, &Ace); + if (NT_SUCCESS(Status)) + { + if (Ace == NULL) + { + Flags |= UF_PASSWD_CANT_CHANGE; + } + else if ((Ace->Mask & USER_CHANGE_PASSWORD) == 0) + { + Flags |= UF_PASSWD_CANT_CHANGE; + } + } + } if (AccountControl & USER_ACCOUNT_DISABLED) Flags |= UF_ACCOUNTDISABLE; @@ -79,8 +145,6 @@ if (AccountControl & USER_PASSWORD_NOT_REQUIRED) Flags |= UF_PASSWD_NOTREQD; - -// UF_PASSWD_CANT_CHANGE if (AccountControl & USER_ACCOUNT_AUTO_LOCKED) Flags |= UF_LOCKOUT; @@ -185,6 +249,87 @@ static +NET_API_STATUS +GetUserDacl(IN SAM_HANDLE UserHandle, + OUT PACL *Dacl) +{ + PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; + PACL SamDacl; + PACL LocalDacl; + BOOLEAN Defaulted; + BOOLEAN Present; + ACL_SIZE_INFORMATION AclSize; + NET_API_STATUS ApiStatus; + NTSTATUS Status; + + TRACE("(%p %p)\n", UserHandle, Dacl); + + *Dacl = NULL; + + Status = SamQuerySecurityObject(UserHandle, + DACL_SECURITY_INFORMATION, + &SecurityDescriptor); + if (!NT_SUCCESS(Status)) + { + TRACE("SamQuerySecurityObject() failed (Status 0x%08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, + &Present, + &SamDacl, + &Defaulted); + if (!NT_SUCCESS(Status)) + { + TRACE("RtlGetDaclSecurityDescriptor() failed (Status 0x%08lx)\n", Status); + ApiStatus = NERR_InternalError; + goto done; + } + + if (Present == FALSE) + { + TRACE("No DACL present\n"); + ApiStatus = NERR_Success; + goto done; + } + + Status = RtlQueryInformationAcl(SamDacl, + &AclSize, + sizeof(AclSize), + AclSizeInformation); + if (!NT_SUCCESS(Status)) + { + TRACE("RtlQueryInformationAcl() failed (Status 0x%08lx)\n", Status); + ApiStatus = NERR_InternalError; + goto done; + } + + LocalDacl = HeapAlloc(GetProcessHeap(), 0, AclSize.AclBytesInUse); + if (LocalDacl == NULL) + { + TRACE("Memory allocation failed\n"); + ApiStatus = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + RtlCopyMemory(LocalDacl, SamDacl, AclSize.AclBytesInUse); + + *Dacl = LocalDacl; + + ApiStatus = NERR_Success; + +done: + if (SecurityDescriptor != NULL) + SamFreeMemory(SecurityDescriptor); + + TRACE("done (ApiStatus: 0x%08lx)\n", ApiStatus); + + return ApiStatus; +} + + +static VOID FreeUserInfo(PUSER_ALL_INFORMATION UserInfo) { @@ -238,6 +383,7 @@ UNICODE_STRING LogonServer = RTL_CONSTANT_STRING(L"\\\\*"); PUSER_ALL_INFORMATION UserInfo = NULL; LPVOID LocalBuffer = NULL; + PACL Dacl = NULL; PUSER_INFO_0 UserInfo0; PUSER_INFO_1 UserInfo1; PUSER_INFO_2 UserInfo2; @@ -264,6 +410,14 @@ goto done; } + if ((level == 1) || (level == 2) || (level == 3) || + (level == 4) || (level == 20) || (level == 23)) + { + ApiStatus = GetUserDacl(UserHandle, &Dacl); + if (ApiStatus != NERR_Success) + goto done; + } + switch (level) { case 0: @@ -531,7 +685,8 @@ Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); } - UserInfo1->usri1_flags = GetAccountFlags(UserInfo->UserAccountControl); + UserInfo1->usri1_flags = GetAccountFlags(UserInfo->UserAccountControl, + Dacl); if (UserInfo->ScriptPath.Length > 0) { @@ -586,7 +741,8 @@ Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); } - UserInfo2->usri2_flags = GetAccountFlags(UserInfo->UserAccountControl); + UserInfo2->usri2_flags = GetAccountFlags(UserInfo->UserAccountControl, + Dacl); if (UserInfo->ScriptPath.Length > 0) { @@ -734,7 +890,8 @@ Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); } - UserInfo3->usri3_flags = GetAccountFlags(UserInfo->UserAccountControl); + UserInfo3->usri3_flags = GetAccountFlags(UserInfo->UserAccountControl, + Dacl); if (UserInfo->ScriptPath.Length > 0) { @@ -911,7 +1068,8 @@ Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); } - UserInfo4->usri4_flags = GetAccountFlags(UserInfo->UserAccountControl); + UserInfo4->usri4_flags = GetAccountFlags(UserInfo->UserAccountControl, + Dacl); if (UserInfo->ScriptPath.Length > 0) { @@ -1267,7 +1425,8 @@ Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); } - UserInfo20->usri20_flags = GetAccountFlags(UserInfo->UserAccountControl); + UserInfo20->usri20_flags = GetAccountFlags(UserInfo->UserAccountControl, + Dacl); UserInfo20->usri20_user_id = RelativeId; break; @@ -1310,7 +1469,8 @@ Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); } - UserInfo23->usri23_flags = GetAccountFlags(UserInfo->UserAccountControl); + UserInfo23->usri23_flags = GetAccountFlags(UserInfo->UserAccountControl, + Dacl); /* FIXME: usri23_user_sid */ break; @@ -1319,6 +1479,9 @@ done: if (UserInfo != NULL) FreeUserInfo(UserInfo); + + if (Dacl != NULL) + HeapFree(GetProcessHeap(), 0, Dacl); if (ApiStatus == NERR_Success) { @@ -2530,7 +2693,7 @@ TRACE("RID: %lu\n", CurrentUser->RelativeId); Status = SamOpenUser(EnumContext->AccountDomainHandle, //BuiltinDomainHandle, - USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT, + READ_CONTROL | USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT, CurrentUser->RelativeId, &UserHandle); if (!NT_SUCCESS(Status)) @@ -2861,7 +3024,7 @@ /* Open the user object */ Status = SamOpenUser(AccountDomainHandle, - USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT, + READ_CONTROL | USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT, RelativeIds[0], &UserHandle); if (!NT_SUCCESS(Status))