[NETAPI32]
authorEric Kohl <eric.kohl@reactos.org>
Tue, 26 Nov 2013 16:56:33 +0000 (16:56 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Tue, 26 Nov 2013 16:56:33 +0000 (16:56 +0000)
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.

svn path=/trunk/; revision=61103

reactos/dll/win32/netapi32/user.c

index 0780c2e..56252ba 100644 (file)
@@ -65,11 +65,77 @@ DeltaTimeToSeconds(LARGE_INTEGER DeltaTime)
 }
 
 
+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;
@@ -80,8 +146,6 @@ GetAccountFlags(ULONG AccountControl)
     if (AccountControl & USER_PASSWORD_NOT_REQUIRED)
         Flags |= UF_PASSWD_NOTREQD;
 
-//    UF_PASSWD_CANT_CHANGE
-
     if (AccountControl & USER_ACCOUNT_AUTO_LOCKED)
         Flags |= UF_LOCKOUT;
 
@@ -184,6 +248,87 @@ GetPasswordAge(IN PLARGE_INTEGER PasswordLastSet)
 }
 
 
+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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
     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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
         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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
                 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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
                 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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
                 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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
                 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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
                 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 @@ BuildUserInfoBuffer(SAM_HANDLE UserHandle,
                 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;
@@ -1320,6 +1480,9 @@ done:
     if (UserInfo != NULL)
         FreeUserInfo(UserInfo);
 
+    if (Dacl != NULL)
+        HeapFree(GetProcessHeap(), 0, Dacl);
+
     if (ApiStatus == NERR_Success)
     {
         *Buffer = LocalBuffer;
@@ -2530,7 +2693,7 @@ NetUserEnum(LPCWSTR servername,
         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 @@ NetUserGetInfo(LPCWSTR servername,
 
     /* 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))