diff --git a/reactos/dll/win32/samsrv/database.c b/reactos/dll/win32/samsrv/database.c index 34f55674081..3d2a8825ce1 100644 --- a/reactos/dll/win32/samsrv/database.c +++ b/reactos/dll/win32/samsrv/database.c @@ -157,8 +157,7 @@ SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject, 0, NULL); - if ((ObjectType == SamDbAliasObject) || - (ObjectType == SamDbGroupObject)) + if (ObjectType == SamDbAliasObject) { /* Open the object key */ RtlInitUnicodeString(&KeyName, @@ -244,9 +243,6 @@ SampCreateDbObject(IN PSAM_DB_OBJECT ParentObject, NewObject->RelativeId = RelativeId; NewObject->ParentObject = ParentObject; - if (ParentObject != NULL) - ParentObject->RefCount++; - *DbObject = NewObject; return STATUS_SUCCESS; @@ -313,8 +309,7 @@ SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject, KEY_ALL_ACCESS, &ObjectAttributes); - if ((ObjectType == SamDbAliasObject) || - (ObjectType == SamDbGroupObject)) + if (ObjectType == SamDbAliasObject) { /* Open the object key */ RtlInitUnicodeString(&KeyName, @@ -396,9 +391,6 @@ SampOpenDbObject(IN PSAM_DB_OBJECT ParentObject, NewObject->RelativeId = RelativeId; NewObject->ParentObject = ParentObject; - if (ParentObject != NULL) - ParentObject->RefCount++; - *DbObject = NewObject; return STATUS_SUCCESS; @@ -475,14 +467,144 @@ SampCloseDbObject(PSAM_DB_OBJECT DbObject) RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject); - if (ParentObject != NULL) - { - ParentObject->RefCount--; + return Status; +} - if (ParentObject->RefCount == 0) - Status = SampCloseDbObject(ParentObject); + +NTSTATUS +SampDeleteAccountDbObject(PSAM_DB_OBJECT DbObject) +{ + LPCWSTR ContainerName; + LPWSTR AccountName = NULL; + HKEY ContainerKey; + HKEY NamesKey; + ULONG Length = 0; + NTSTATUS Status = STATUS_SUCCESS; + + TRACE("(%p)\n", DbObject); + + /* Server and Domain objects cannot be deleted */ + switch (DbObject->ObjectType) + { + case SamDbAliasObject: + ContainerName = L"Aliases"; + break; + + case SamDbGroupObject: + ContainerName = L"Groups"; + break; + + case SamDbUserObject: + ContainerName = L"Users"; + break; + + default: + return STATUS_INVALID_PARAMETER; } + /* Get the account name */ + Status = SampGetObjectAttribute(DbObject, + L"Name", + NULL, + NULL, + &Length); + if (Status != STATUS_BUFFER_OVERFLOW) + { + TRACE("Status 0x%08lx\n", Status); + goto done; + } + + AccountName = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + Length); + if (AccountName == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + Status = SampGetObjectAttribute(DbObject, + L"Name", + NULL, + (PVOID)AccountName, + &Length); + if (!NT_SUCCESS(Status)) + { + TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status); + goto done; + } + + if (DbObject->KeyHandle != NULL) + NtClose(DbObject->KeyHandle); + + if (DbObject->ObjectType == SamDbAliasObject) + { + if (DbObject->MembersKeyHandle != NULL) + NtClose(DbObject->MembersKeyHandle); + + SampRegDeleteKey(DbObject->KeyHandle, + L"Members"); + } + + /* Open the domain container key */ + Status = SampRegOpenKey(DbObject->ParentObject->KeyHandle, + ContainerName, + DELETE | KEY_SET_VALUE, + &ContainerKey); + if (!NT_SUCCESS(Status)) + { + TRACE("SampRegOpenKey failed (Status 0x%08lx)\n", Status); + goto done; + } + + /* Open the Names key */ + Status = SampRegOpenKey(ContainerKey, + L"Names", + KEY_SET_VALUE, + &NamesKey); + if (!NT_SUCCESS(Status)) + { + TRACE("SampRegOpenKey failed (Status 0x%08lx)\n", Status); + goto done; + } + + /* Remove the account from the Names key */ + Status = SampRegDeleteValue(NamesKey, + AccountName); + if (!NT_SUCCESS(Status)) + { + TRACE("SampRegDeleteValue failed (Status 0x%08lx)\n", Status); + goto done; + } + + /* Remove the account key from the container */ + Status = SampRegDeleteKey(ContainerKey, + DbObject->Name); + if (!NT_SUCCESS(Status)) + { + TRACE("SampRegDeleteKey failed (Status 0x%08lx)\n", Status); + goto done; + } + + /* Release the database object name */ + if (DbObject->Name != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject->Name); + + /* Release the database object */ + RtlFreeHeap(RtlGetProcessHeap(), 0, DbObject); + + Status = STATUS_SUCCESS; + +done: + if (NamesKey != NULL) + SampRegCloseKey(NamesKey); + + if (ContainerKey != NULL) + SampRegCloseKey(ContainerKey); + + if (AccountName != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, AccountName); + return Status; } diff --git a/reactos/dll/win32/samsrv/samrpc.c b/reactos/dll/win32/samsrv/samrpc.c index dcdb4cef3d3..499544391ca 100644 --- a/reactos/dll/win32/samsrv/samrpc.c +++ b/reactos/dll/win32/samsrv/samrpc.c @@ -3952,7 +3952,7 @@ SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle, &UserObject); if (!NT_SUCCESS(Status)) { - ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status); + TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status); goto done; } @@ -3962,7 +3962,7 @@ SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle, Attributes); if (!NT_SUCCESS(Status)) { - ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status); + TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status); goto done; } @@ -3971,7 +3971,7 @@ SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle, MemberId); if (!NT_SUCCESS(Status)) { - ERR("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status); + TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status); } done: @@ -3987,8 +3987,58 @@ NTSTATUS NTAPI SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PSAM_DB_OBJECT GroupObject; + ULONG Length = 0; + NTSTATUS Status; + + TRACE("(%p)\n", GroupHandle); + + /* Validate the group handle */ + Status = SampValidateDbObject(*GroupHandle, + SamDbGroupObject, + DELETE, + &GroupObject); + if (!NT_SUCCESS(Status)) + { + TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status); + return Status; + } + + /* Fail, if the group is built-in */ + if (GroupObject->RelativeId < 1000) + { + TRACE("You can not delete a special account!\n"); + return STATUS_SPECIAL_ACCOUNT; + } + + /* Get the length of the Members attribute */ + SampGetObjectAttribute(GroupObject, + L"Members", + NULL, + NULL, + &Length); + + /* Fail, if the group has members */ + if (Length != 0) + { + TRACE("There are still members in the group!\n"); + return STATUS_MEMBER_IN_GROUP; + } + + /* FIXME: Remove the group from all aliases */ + + /* Delete the group from the database */ + Status = SampDeleteAccountDbObject(GroupObject); + if (!NT_SUCCESS(Status)) + { + TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status); + return Status; + } + + /* Invalidate the handle */ + *GroupHandle = NULL; + + return STATUS_SUCCESS; } diff --git a/reactos/dll/win32/samsrv/samsrv.h b/reactos/dll/win32/samsrv/samsrv.h index c07d0ea40a1..370f4e5b886 100644 --- a/reactos/dll/win32/samsrv/samsrv.h +++ b/reactos/dll/win32/samsrv/samsrv.h @@ -29,7 +29,6 @@ typedef enum _SAM_DB_OBJECT_TYPE { SamDbIgnoreObject, - SamDbContainerObject, SamDbServerObject, SamDbDomainObject, SamDbAliasObject, @@ -45,7 +44,7 @@ typedef struct _SAM_DB_OBJECT ACCESS_MASK Access; LPWSTR Name; HANDLE KeyHandle; - HANDLE MembersKeyHandle; // only used by Aliases and Groups + HANDLE MembersKeyHandle; // only used by Aliases ULONG RelativeId; struct _SAM_DB_OBJECT *ParentObject; } SAM_DB_OBJECT, *PSAM_DB_OBJECT; @@ -142,6 +141,9 @@ SampValidateDbObject(SAMPR_HANDLE Handle, NTSTATUS SampCloseDbObject(PSAM_DB_OBJECT DbObject); +NTSTATUS +SampDeleteAccountDbObject(PSAM_DB_OBJECT DbObject); + NTSTATUS SampSetObjectAttribute(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName,