[SAMSRV]
authorEric Kohl <eric.kohl@reactos.org>
Mon, 2 Jul 2012 23:09:20 +0000 (23:09 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Mon, 2 Jul 2012 23:09:20 +0000 (23:09 +0000)
- Store all fixed size user attributes in the registry value "F".
- Initialize fixed size domain attributes in SampCreateUserAccount and SamrCreateUserInDomain.
- Implement most information classes of SamrQueryInformationUser.
- Disable all informationclasses of SamrSetInformationUser that store fixed size attributes.

svn path=/trunk/; revision=56820

reactos/dll/win32/samsrv/samrpc.c
reactos/dll/win32/samsrv/samsrv.h
reactos/dll/win32/samsrv/setup.c

index fa1ea3c..3a2f94e 100644 (file)
@@ -1712,6 +1712,7 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
                        OUT unsigned long *RelativeId)
 {
     SAM_DOMAIN_FIXED_DATA FixedDomainData;
+    SAM_USER_FIXED_DATA FixedUserData;
     PSAM_DB_OBJECT DomainObject;
     PSAM_DB_OBJECT UserObject;
     ULONG ulSize;
@@ -1809,6 +1810,24 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
         return Status;
     }
 
+    /* Initialize fixed user data */
+    memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
+    FixedUserData.Version = 1;
+
+    FixedUserData.UserId = ulRid;
+
+    /* Set fixed user data attribute */
+    Status = SampSetObjectAttribute(UserObject,
+                                    L"F",
+                                    REG_BINARY,
+                                    (LPVOID)&FixedUserData,
+                                    sizeof(SAM_USER_FIXED_DATA));
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        return Status;
+    }
+
     /* Set the name attribute */
     Status = SampSetObjectAttribute(UserObject,
                                     L"Name",
@@ -3158,191 +3177,978 @@ SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
     return STATUS_NOT_IMPLEMENTED;
 }
 
+
 static
 NTSTATUS
 SampQueryUserName(PSAM_DB_OBJECT UserObject,
                   PSAMPR_USER_INFO_BUFFER *Buffer)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-/* Function 36 */
-NTSTATUS
-NTAPI
-SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
-                         IN USER_INFORMATION_CLASS UserInformationClass,
-                         OUT PSAMPR_USER_INFO_BUFFER *Buffer)
-{
-    PSAM_DB_OBJECT UserObject;
-    ACCESS_MASK DesiredAccess;
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
     NTSTATUS Status;
 
-    TRACE("SamrQueryInformationUser(%p %lu %p)\n",
-          UserHandle, UserInformationClass, Buffer);
+    *Buffer = NULL;
 
-    switch (UserInformationClass)
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"Name",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
     {
-        case UserGeneralInformation:
-        case UserNameInformation:
-        case UserAccountNameInformation:
-        case UserFullNameInformation:
-        case UserPrimaryGroupInformation:
-        case UserAdminCommentInformation:
-            DesiredAccess = USER_READ_GENERAL;
-            break;
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
 
+    InfoBuffer->Name.UserName.Length = Length - sizeof(WCHAR);
+    InfoBuffer->Name.UserName.MaximumLength = Length;
+    InfoBuffer->Name.UserName.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->Name.UserName.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
 
-        default:
-            return STATUS_INVALID_INFO_CLASS;
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"Name",
+                                    NULL,
+                                    (PVOID)InfoBuffer->Name.UserName.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
     }
 
-    /* Validate the domain handle */
-    Status = SampValidateDbObject(UserHandle,
-                                  SamDbUserObject,
-                                  DesiredAccess,
-                                  &UserObject);
+    Length = 0;
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"FullName",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->Name.FullName.Length = Length - sizeof(WCHAR);
+    InfoBuffer->Name.FullName.MaximumLength = Length;
+    InfoBuffer->Name.FullName.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->Name.FullName.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"FullName",
+                                    NULL,
+                                    (PVOID)InfoBuffer->Name.FullName.Buffer,
+                                    &Length);
     if (!NT_SUCCESS(Status))
     {
-        TRACE("failed with status 0x%08lx\n", Status);
-        return Status;
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
     }
 
-    switch (UserInformationClass)
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
     {
-        case UserNameInformation:
-            Status = SampQueryUserName(UserObject,
-                                       Buffer);
-            break;
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->Name.UserName.Buffer != NULL)
+                midl_user_free(InfoBuffer->Name.UserName.Buffer);
 
-        default:
-            Status = STATUS_INVALID_INFO_CLASS;
+            if (InfoBuffer->Name.FullName.Buffer != NULL)
+                midl_user_free(InfoBuffer->Name.FullName.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
     }
 
     return Status;
 }
 
-/* Function 37 */
-NTSTATUS
-NTAPI
-SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
-                       IN USER_INFORMATION_CLASS UserInformationClass,
-                       IN PSAMPR_USER_INFO_BUFFER Buffer)
+
+static NTSTATUS
+SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
+                         PSAMPR_USER_INFO_BUFFER *Buffer)
 {
-    PSAM_DB_OBJECT UserObject;
-    ACCESS_MASK DesiredAccess;
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
     NTSTATUS Status;
 
-    TRACE("SamrSetInformationUser(%p %lu %p)\n",
-          UserHandle, UserInformationClass, Buffer);
+    *Buffer = NULL;
 
-    switch (UserInformationClass)
-    {
-        case UserNameInformation:
-        case UserAccountNameInformation:
-        case UserFullNameInformation:
-        case UserPrimaryGroupInformation:
-        case UserHomeInformation:
-        case UserScriptInformation:
-        case UserProfileInformation:
-        case UserAdminCommentInformation:
-        case UserWorkStationsInformation:
-        case UserControlInformation:
-        case UserExpiresInformation:
-            DesiredAccess = USER_WRITE_ACCOUNT;
-            break;
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
 
-        case UserSetPasswordInformation:
-            DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
-            break;
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"Name",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
 
-        default:
-            return STATUS_INVALID_INFO_CLASS;
+    InfoBuffer->AccountName.UserName.Length = Length - sizeof(WCHAR);
+    InfoBuffer->AccountName.UserName.MaximumLength = Length;
+    InfoBuffer->AccountName.UserName.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->AccountName.UserName.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
     }
 
-    /* Validate the domain handle */
-    Status = SampValidateDbObject(UserHandle,
-                                  SamDbUserObject,
-                                  DesiredAccess,
-                                  &UserObject);
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"Name",
+                                    NULL,
+                                    (PVOID)InfoBuffer->AccountName.UserName.Buffer,
+                                    &Length);
     if (!NT_SUCCESS(Status))
     {
-        TRACE("failed with status 0x%08lx\n", Status);
-        return Status;
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
     }
 
-    switch (UserInformationClass)
-    {
-//        case UserGeneralInformation:
-//        case UserPreferencesInformation:
-//        case UserLogonHoursInformation:
+    *Buffer = InfoBuffer;
 
-        case UserNameInformation:
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"Name",
-                                            REG_SZ,
-                                            Buffer->Name.UserName.Buffer,
-                                            Buffer->Name.UserName.MaximumLength);
-            if (!NT_SUCCESS(Status))
-                break;
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->AccountName.UserName.Buffer != NULL)
+                midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
 
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"FullName",
-                                            REG_SZ,
-                                            Buffer->Name.FullName.Buffer,
-                                            Buffer->Name.FullName.MaximumLength);
-            break;
+            midl_user_free(InfoBuffer);
+        }
+    }
 
-        case UserAccountNameInformation:
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"Name",
-                                            REG_SZ,
-                                            Buffer->AccountName.UserName.Buffer,
-                                            Buffer->AccountName.UserName.MaximumLength);
-            break;
+    return Status;
+}
 
-        case UserFullNameInformation:
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"FullName",
-                                            REG_SZ,
-                                            Buffer->FullName.FullName.Buffer,
-                                            Buffer->FullName.FullName.MaximumLength);
-            break;
 
-        case UserPrimaryGroupInformation:
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"PrimaryGroupId",
-                                            REG_DWORD,
-                                            &Buffer->PrimaryGroup.PrimaryGroupId,
-                                            sizeof(ULONG));
-            break;
+static NTSTATUS
+SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
+                      PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
+    NTSTATUS Status;
 
-        case UserHomeInformation:
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"HomeDirectory",
-                                            REG_SZ,
-                                            Buffer->Home.HomeDirectory.Buffer,
-                                            Buffer->Home.HomeDirectory.MaximumLength);
-            if (!NT_SUCCESS(Status))
-                break;
+    *Buffer = NULL;
 
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"HomeDirectoryDrive",
-                                            REG_SZ,
-                                            Buffer->Home.HomeDirectoryDrive.Buffer,
-                                            Buffer->Home.HomeDirectoryDrive.MaximumLength);
-            break;
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
 
-        case UserScriptInformation:
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"ScriptPath",
-                                            REG_SZ,
-                                            Buffer->Script.ScriptPath.Buffer,
-                                            Buffer->Script.ScriptPath.MaximumLength);
-            break;
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"FullName",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
 
-        case UserProfileInformation:
-            Status = SampSetObjectAttribute(UserObject,
+    InfoBuffer->FullName.FullName.Length = Length - sizeof(WCHAR);
+    InfoBuffer->FullName.FullName.MaximumLength = Length;
+    InfoBuffer->FullName.FullName.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->FullName.FullName.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"FullName",
+                                    NULL,
+                                    (PVOID)InfoBuffer->FullName.FullName.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->FullName.FullName.Buffer != NULL)
+                midl_user_free(InfoBuffer->FullName.FullName.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static
+NTSTATUS
+SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
+                          PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    SAM_USER_FIXED_DATA FixedData;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Length = sizeof(SAM_USER_FIXED_DATA);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"F",
+                                    NULL,
+                                    (PVOID)&FixedData,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static NTSTATUS
+SampQueryUserHome(PSAM_DB_OBJECT UserObject,
+                  PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"HomeDirectory",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->Home.HomeDirectory.Length = Length - sizeof(WCHAR);
+    InfoBuffer->Home.HomeDirectory.MaximumLength = Length;
+    InfoBuffer->Home.HomeDirectory.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->Home.HomeDirectory.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"HomeDirectory",
+                                    NULL,
+                                    (PVOID)InfoBuffer->Home.HomeDirectory.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    Length = 0;
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"HomeDirectoryDrive",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->Home.HomeDirectoryDrive.Length = Length - sizeof(WCHAR);
+    InfoBuffer->Home.HomeDirectoryDrive.MaximumLength = Length;
+    InfoBuffer->Home.HomeDirectoryDrive.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->Home.HomeDirectoryDrive.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"HomeDirectoryDrive",
+                                    NULL,
+                                    (PVOID)InfoBuffer->Home.HomeDirectoryDrive.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
+                midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
+
+            if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
+                midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static NTSTATUS
+SampQueryUserScript(PSAM_DB_OBJECT UserObject,
+                    PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"ScriptPath",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->Script.ScriptPath.Length = Length - sizeof(WCHAR);
+    InfoBuffer->Script.ScriptPath.MaximumLength = Length;
+    InfoBuffer->Script.ScriptPath.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->Script.ScriptPath.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"ScriptPath",
+                                    NULL,
+                                    (PVOID)InfoBuffer->Script.ScriptPath.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
+                midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static NTSTATUS
+SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
+                     PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"ProfilePath",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->Profile.ProfilePath.Length = Length - sizeof(WCHAR);
+    InfoBuffer->Profile.ProfilePath.MaximumLength = Length;
+    InfoBuffer->Profile.ProfilePath.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->Profile.ProfilePath.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"ProfilePath",
+                                    NULL,
+                                    (PVOID)InfoBuffer->Profile.ProfilePath.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
+                midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static NTSTATUS
+SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
+                          PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"AdminComment",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->AdminComment.AdminComment.Length = Length - sizeof(WCHAR);
+    InfoBuffer->AdminComment.AdminComment.MaximumLength = Length;
+    InfoBuffer->AdminComment.AdminComment.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->AdminComment.AdminComment.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"AdminComment",
+                                    NULL,
+                                    (PVOID)InfoBuffer->AdminComment.AdminComment.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
+                midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+
+static NTSTATUS
+SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
+                          PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"WorkStations",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    InfoBuffer->WorkStations.WorkStations.Length = Length - sizeof(WCHAR);
+    InfoBuffer->WorkStations.WorkStations.MaximumLength = Length;
+    InfoBuffer->WorkStations.WorkStations.Buffer = midl_user_allocate(Length);
+    if (InfoBuffer->WorkStations.WorkStations.Buffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    TRACE("Length: %lu\n", Length);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"WorkStations",
+                                    NULL,
+                                    (PVOID)InfoBuffer->WorkStations.WorkStations.Buffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
+                midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
+
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static
+NTSTATUS
+SampQueryUserControl(PSAM_DB_OBJECT UserObject,
+                     PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    SAM_USER_FIXED_DATA FixedData;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Length = sizeof(SAM_USER_FIXED_DATA);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"F",
+                                    NULL,
+                                    (PVOID)&FixedData,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+static
+NTSTATUS
+SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
+                     PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
+    SAM_USER_FIXED_DATA FixedData;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    *Buffer = NULL;
+
+    InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
+    if (InfoBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    Length = sizeof(SAM_USER_FIXED_DATA);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"F",
+                                    NULL,
+                                    (PVOID)&FixedData,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
+    InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
+
+    *Buffer = InfoBuffer;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (InfoBuffer != NULL)
+        {
+            midl_user_free(InfoBuffer);
+        }
+    }
+
+    return Status;
+}
+
+
+/* Function 36 */
+NTSTATUS
+NTAPI
+SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
+                         IN USER_INFORMATION_CLASS UserInformationClass,
+                         OUT PSAMPR_USER_INFO_BUFFER *Buffer)
+{
+    PSAM_DB_OBJECT UserObject;
+    ACCESS_MASK DesiredAccess;
+    NTSTATUS Status;
+
+    TRACE("SamrQueryInformationUser(%p %lu %p)\n",
+          UserHandle, UserInformationClass, Buffer);
+
+    switch (UserInformationClass)
+    {
+        case UserGeneralInformation:
+        case UserNameInformation:
+        case UserAccountNameInformation:
+        case UserFullNameInformation:
+        case UserPrimaryGroupInformation:
+        case UserAdminCommentInformation:
+            DesiredAccess = USER_READ_GENERAL;
+            break;
+
+        case UserLogonHoursInformation:
+        case UserHomeInformation:
+        case UserScriptInformation:
+        case UserProfileInformation:
+        case UserWorkStationsInformation:
+            DesiredAccess = USER_READ_LOGON;
+            break;
+
+        case UserControlInformation:
+        case UserExpiresInformation:
+            DesiredAccess = USER_READ_ACCOUNT;
+            break;
+
+        case UserPreferencesInformation:
+            DesiredAccess = USER_READ_GENERAL |
+                            USER_READ_PREFERENCES;
+            break;
+
+        case UserLogonInformation:
+        case UserAccountInformation:
+            DesiredAccess = USER_READ_GENERAL |
+                            USER_READ_PREFERENCES |
+                            USER_READ_LOGON |
+                            USER_READ_ACCOUNT;
+            break;
+
+        default:
+            return STATUS_INVALID_INFO_CLASS;
+    }
+
+    /* Validate the domain handle */
+    Status = SampValidateDbObject(UserHandle,
+                                  SamDbUserObject,
+                                  DesiredAccess,
+                                  &UserObject);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        return Status;
+    }
+
+    switch (UserInformationClass)
+    {
+//        case UserGeneralInformation:
+//        case UserPreferencesInformation:
+//        case UserLogonInformation:
+//        case UserLogonHoursInformation:
+//        case UserAccountInformation:
+
+        case UserNameInformation:
+            Status = SampQueryUserName(UserObject,
+                                       Buffer);
+            break;
+
+        case UserAccountNameInformation:
+            Status = SampQueryUserAccountName(UserObject,
+                                              Buffer);
+            break;
+
+        case UserFullNameInformation:
+            Status = SampQueryUserFullName(UserObject,
+                                           Buffer);
+            break;
+
+        case UserPrimaryGroupInformation:
+            Status = SampQueryUserPrimaryGroup(UserObject,
+                                               Buffer);
+            break;
+
+        case UserHomeInformation:
+            Status = SampQueryUserHome(UserObject,
+                                       Buffer);
+
+        case UserScriptInformation:
+            Status = SampQueryUserScript(UserObject,
+                                         Buffer);
+            break;
+
+        case UserProfileInformation:
+            Status = SampQueryUserProfile(UserObject,
+                                          Buffer);
+            break;
+
+        case UserAdminCommentInformation:
+            Status = SampQueryUserAdminComment(UserObject,
+                                               Buffer);
+            break;
+
+        case UserWorkStationsInformation:
+            Status = SampQueryUserWorkStations(UserObject,
+                                               Buffer);
+            break;
+
+        case UserControlInformation:
+            Status = SampQueryUserControl(UserObject,
+                                          Buffer);
+            break;
+
+        case UserExpiresInformation:
+            Status = SampQueryUserExpires(UserObject,
+                                          Buffer);
+            break;
+
+        default:
+            Status = STATUS_INVALID_INFO_CLASS;
+    }
+
+    return Status;
+}
+
+/* Function 37 */
+NTSTATUS
+NTAPI
+SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
+                       IN USER_INFORMATION_CLASS UserInformationClass,
+                       IN PSAMPR_USER_INFO_BUFFER Buffer)
+{
+    PSAM_DB_OBJECT UserObject;
+    ACCESS_MASK DesiredAccess;
+    NTSTATUS Status;
+
+    TRACE("SamrSetInformationUser(%p %lu %p)\n",
+          UserHandle, UserInformationClass, Buffer);
+
+    switch (UserInformationClass)
+    {
+        case UserNameInformation:
+        case UserAccountNameInformation:
+        case UserFullNameInformation:
+        case UserPrimaryGroupInformation:
+        case UserHomeInformation:
+        case UserScriptInformation:
+        case UserProfileInformation:
+        case UserAdminCommentInformation:
+        case UserWorkStationsInformation:
+        case UserControlInformation:
+        case UserExpiresInformation:
+            DesiredAccess = USER_WRITE_ACCOUNT;
+            break;
+
+        case UserSetPasswordInformation:
+            DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
+            break;
+
+        default:
+            return STATUS_INVALID_INFO_CLASS;
+    }
+
+    /* Validate the domain handle */
+    Status = SampValidateDbObject(UserHandle,
+                                  SamDbUserObject,
+                                  DesiredAccess,
+                                  &UserObject);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        return Status;
+    }
+
+    switch (UserInformationClass)
+    {
+//        case UserGeneralInformation:
+//        case UserPreferencesInformation:
+//        case UserLogonHoursInformation:
+
+        case UserNameInformation:
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"Name",
+                                            REG_SZ,
+                                            Buffer->Name.UserName.Buffer,
+                                            Buffer->Name.UserName.MaximumLength);
+            if (!NT_SUCCESS(Status))
+                break;
+
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"FullName",
+                                            REG_SZ,
+                                            Buffer->Name.FullName.Buffer,
+                                            Buffer->Name.FullName.MaximumLength);
+            break;
+
+        case UserAccountNameInformation:
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"Name",
+                                            REG_SZ,
+                                            Buffer->AccountName.UserName.Buffer,
+                                            Buffer->AccountName.UserName.MaximumLength);
+            break;
+
+        case UserFullNameInformation:
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"FullName",
+                                            REG_SZ,
+                                            Buffer->FullName.FullName.Buffer,
+                                            Buffer->FullName.FullName.MaximumLength);
+            break;
+
+/*
+        case UserPrimaryGroupInformation:
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"PrimaryGroupId",
+                                            REG_DWORD,
+                                            &Buffer->PrimaryGroup.PrimaryGroupId,
+                                            sizeof(ULONG));
+            break;
+*/
+
+        case UserHomeInformation:
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"HomeDirectory",
+                                            REG_SZ,
+                                            Buffer->Home.HomeDirectory.Buffer,
+                                            Buffer->Home.HomeDirectory.MaximumLength);
+            if (!NT_SUCCESS(Status))
+                break;
+
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"HomeDirectoryDrive",
+                                            REG_SZ,
+                                            Buffer->Home.HomeDirectoryDrive.Buffer,
+                                            Buffer->Home.HomeDirectoryDrive.MaximumLength);
+            break;
+
+        case UserScriptInformation:
+            Status = SampSetObjectAttribute(UserObject,
+                                            L"ScriptPath",
+                                            REG_SZ,
+                                            Buffer->Script.ScriptPath.Buffer,
+                                            Buffer->Script.ScriptPath.MaximumLength);
+            break;
+
+        case UserProfileInformation:
+            Status = SampSetObjectAttribute(UserObject,
                                             L"ProfilePath",
                                             REG_SZ,
                                             Buffer->Profile.ProfilePath.Buffer,
@@ -3376,6 +4182,7 @@ SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
                                             Buffer->SetPassword.Password.MaximumLength);
             break;
 
+/*
         case UserControlInformation:
             Status = SampSetObjectAttribute(UserObject,
                                             L"UserAccountControl",
@@ -3383,7 +4190,8 @@ SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
                                             &Buffer->Control.UserAccountControl,
                                             sizeof(ULONG));
             break;
-
+*/
+/*
         case UserExpiresInformation:
             Status = SampSetObjectAttribute(UserObject,
                                             L"AccountExpires",
@@ -3391,6 +4199,7 @@ SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
                                             &Buffer->Expires.AccountExpires,
                                             sizeof(OLD_LARGE_INTEGER));
             break;
+*/
 
 //        case UserInternal1Information:
 //        case UserParametersInformation:
index ff734c2..edde478 100644 (file)
@@ -73,6 +73,26 @@ typedef struct _SAM_DOMAIN_FIXED_DATA
     BOOLEAN UasCompatibilityRequired;
 } SAM_DOMAIN_FIXED_DATA, *PSAM_DOMAIN_FIXED_DATA;
 
+typedef struct _SAM_USER_FIXED_DATA
+{
+    ULONG Version;
+    ULONG Reserved;
+    LARGE_INTEGER LastLogon;
+    LARGE_INTEGER LastLogoff;
+    LARGE_INTEGER PasswordLastSet;
+    LARGE_INTEGER AccountExpires;
+    LARGE_INTEGER LastBadPasswordTime;
+    ULONG UserId;
+    ULONG PrimaryGroupId;
+    ULONG UserAccountControl;
+    USHORT CountryCode;
+    USHORT CodePage;
+    USHORT BadPasswordCount;
+    USHORT LogonCount;
+    USHORT AdminCount;
+    USHORT OperatorCount;
+} SAM_USER_FIXED_DATA, *PSAM_USER_FIXED_DATA;
+
 /* database.c */
 
 NTSTATUS
index fc42013..c3438bc 100644 (file)
@@ -223,11 +223,18 @@ SampCreateUserAccount(HKEY hDomainKey,
                       LPCWSTR lpAccountName,
                       ULONG ulRelativeId)
 {
+    SAM_USER_FIXED_DATA FixedUserData;
     DWORD dwDisposition;
     WCHAR szAccountKeyName[32];
     HKEY hAccountKey = NULL;
     HKEY hNamesKey = NULL;
 
+    /* Initialize fixed user data */
+    memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
+    FixedUserData.Version = 1;
+
+    FixedUserData.UserId = ulRelativeId;
+
     swprintf(szAccountKeyName, L"Users\\%08lX", ulRelativeId);
 
     if (!RegCreateKeyExW(hDomainKey,
@@ -240,6 +247,13 @@ SampCreateUserAccount(HKEY hDomainKey,
                          &hAccountKey,
                          &dwDisposition))
     {
+        RegSetValueEx(hAccountKey,
+                      L"F",
+                      0,
+                      REG_BINARY,
+                      (LPVOID)&FixedUserData,
+                      sizeof(SAM_USER_FIXED_DATA));
+
         RegSetValueEx(hAccountKey,
                       L"Name",
                       0,