From 2d7441f3ce7f854b1204a2d5c7be781e7fc62514 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Wed, 8 Aug 2012 21:17:17 +0000 Subject: [PATCH] [SAMLIB/SAMSRV] Implement SamCreateUser2InDomain / SamrCreateUser2InDomain (untested) and SamLookupNamesInDomain / SamrLookupNamesInDomain. svn path=/trunk/; revision=57054 --- reactos/dll/win32/samlib/samlib.c | 120 ++++++- reactos/dll/win32/samlib/samlib.spec | 2 +- reactos/dll/win32/samsrv/samrpc.c | 460 ++++++++++++++++++++++++++- reactos/include/ddk/ntsam.h | 10 + 4 files changed, 584 insertions(+), 8 deletions(-) diff --git a/reactos/dll/win32/samlib/samlib.c b/reactos/dll/win32/samlib/samlib.c index dea21b53237..7c693c1467c 100644 --- a/reactos/dll/win32/samlib/samlib.c +++ b/reactos/dll/win32/samlib/samlib.c @@ -191,6 +191,9 @@ SamCreateAliasInDomain(IN SAM_HANDLE DomainHandle, TRACE("SamCreateAliasInDomain(%p %p 0x%08x %p %p)\n", DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId); + *AliasHandle = NULL; + *RelativeId = 0; + RpcTryExcept { Status = SamrCreateAliasInDomain((SAMPR_HANDLE)DomainHandle, @@ -222,6 +225,9 @@ SamCreateGroupInDomain(IN SAM_HANDLE DomainHandle, TRACE("SamCreateGroupInDomain(%p %p 0x%08x %p %p)\n", DomainHandle, AccountName, DesiredAccess, GroupHandle, RelativeId); + *GroupHandle = NULL; + *RelativeId = 0; + RpcTryExcept { Status = SamrCreateGroupInDomain((SAMPR_HANDLE)DomainHandle, @@ -240,6 +246,46 @@ SamCreateGroupInDomain(IN SAM_HANDLE DomainHandle, } +NTSTATUS +NTAPI +SamCreateUser2InDomain(IN SAM_HANDLE DomainHandle, + IN PUNICODE_STRING AccountName, + IN ULONG AccountType, + IN ACCESS_MASK DesiredAccess, + OUT PSAM_HANDLE UserHandle, + OUT PULONG GrantedAccess, + OUT PULONG RelativeId) +{ + NTSTATUS Status; + + TRACE("SamCreateUser2InDomain(%p %p %lu 0x%08x %p %p %p)\n", + DomainHandle, AccountName, AccountType, DesiredAccess, + UserHandle, GrantedAccess, RelativeId); + + *UserHandle = NULL; + *RelativeId = 0; + + RpcTryExcept + { + Status = SamrCreateUser2InDomain((SAMPR_HANDLE)DomainHandle, + (PRPC_UNICODE_STRING)AccountName, + AccountType, + DesiredAccess, + (SAMPR_HANDLE *)UserHandle, + GrantedAccess, + RelativeId); + + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + Status = I_RpcMapWin32Status(RpcExceptionCode()); + } + RpcEndExcept; + + return Status; +} + + NTSTATUS NTAPI SamCreateUserInDomain(IN SAM_HANDLE DomainHandle, @@ -253,6 +299,9 @@ SamCreateUserInDomain(IN SAM_HANDLE DomainHandle, TRACE("SamCreateUserInDomain(%p %p 0x%08x %p %p)\n", DomainHandle, AccountName, DesiredAccess, UserHandle, RelativeId); + *UserHandle = NULL; + *RelativeId = 0; + RpcTryExcept { Status = SamrCreateUserInDomain((SAMPR_HANDLE)DomainHandle, @@ -605,8 +654,75 @@ SamLookupNamesInDomain(IN SAM_HANDLE DomainHandle, OUT PULONG *RelativeIds, OUT PSID_NAME_USE *Use) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + SAMPR_ULONG_ARRAY RidBuffer = {0, NULL}; + SAMPR_ULONG_ARRAY UseBuffer = {0, NULL}; + NTSTATUS Status; + + TRACE("SamLookupNamesInDomain(%p %lu %p %p %p)\n", + DomainHandle, Count, Names, RelativeIds, Use); + + *RelativeIds = NULL; + *Use = NULL; + + RidBuffer.Element = NULL; + UseBuffer.Element = NULL; + + RpcTryExcept + { + Status = SamrLookupNamesInDomain((SAMPR_HANDLE)DomainHandle, + Count, + (PRPC_UNICODE_STRING)Names, + &RidBuffer, + &UseBuffer); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + Status = I_RpcMapWin32Status(RpcExceptionCode()); + } + RpcEndExcept; + + if (NT_SUCCESS(Status)) + { + *RelativeIds = midl_user_allocate(Count * sizeof(ULONG)); + if (*RelativeIds == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + *Use = midl_user_allocate(Count * sizeof(SID_NAME_USE)); + if (*Use == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + RtlCopyMemory(*RelativeIds, + RidBuffer.Element, + Count * sizeof(ULONG)); + + RtlCopyMemory(*Use, + UseBuffer.Element, + Count * sizeof(SID_NAME_USE)); + } + +done: + if (!NT_SUCCESS(Status)) + { + if (*RelativeIds != NULL) + midl_user_free(*RelativeIds); + + if (*Use != NULL) + midl_user_free(*Use); + } + + if (RidBuffer.Element != NULL) + midl_user_free(RidBuffer.Element); + + if (UseBuffer.Element != NULL) + midl_user_free(UseBuffer.Element); + + return Status; } diff --git a/reactos/dll/win32/samlib/samlib.spec b/reactos/dll/win32/samlib/samlib.spec index 37ee98484a9..68b1946f3df 100644 --- a/reactos/dll/win32/samlib/samlib.spec +++ b/reactos/dll/win32/samlib/samlib.spec @@ -9,7 +9,7 @@ @ stub SamConnectWithCreds @ stdcall SamCreateAliasInDomain(ptr ptr long ptr ptr) @ stdcall SamCreateGroupInDomain(ptr ptr long ptr ptr) -@ stub SamCreateUser2InDomain +@ stdcall SamCreateUser2InDomain(ptr ptr long long ptr ptr ptr) @ stdcall SamCreateUserInDomain(ptr ptr long ptr ptr) @ stub SamDeleteAlias @ stub SamDeleteGroup diff --git a/reactos/dll/win32/samsrv/samrpc.c b/reactos/dll/win32/samsrv/samrpc.c index 4a3c30222ae..ed3ea75f10f 100644 --- a/reactos/dll/win32/samsrv/samrpc.c +++ b/reactos/dll/win32/samsrv/samrpc.c @@ -2840,15 +2840,212 @@ done: NTSTATUS NTAPI SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle, - IN unsigned long Count, + IN ULONG Count, IN RPC_UNICODE_STRING Names[], OUT PSAMPR_ULONG_ARRAY RelativeIds, OUT PSAMPR_ULONG_ARRAY Use) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PSAM_DB_OBJECT DomainObject; + HANDLE AccountsKeyHandle; + HANDLE NamesKeyHandle; + ULONG MappedCount = 0; + ULONG DataLength; + ULONG i; + ULONG RelativeId; + NTSTATUS Status; + + TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n", + DomainHandle, Count, Names, RelativeIds, Use); + + /* Validate the domain handle */ + Status = SampValidateDbObject(DomainHandle, + SamDbDomainObject, + DOMAIN_LOOKUP, + &DomainObject); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + RelativeIds->Count = 0; + Use->Count = 0; + + if (Count == 0) + return STATUS_SUCCESS; + + /* Allocate the relative IDs array */ + RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG)); + if (RelativeIds->Element == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + /* Allocate the use array */ + Use->Element = midl_user_allocate(Count * sizeof(ULONG)); + if (Use->Element == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + RelativeIds->Count = Count; + Use->Count = Count; + + for (i = 0; i < Count; i++) + { + TRACE("Name: %S\n", Names[i].Buffer); + + RelativeId = 0; + + /* Lookup aliases */ + Status = SampRegOpenKey(DomainObject->KeyHandle, + L"Aliases", + KEY_READ, + &AccountsKeyHandle); + if (NT_SUCCESS(Status)) + { + Status = SampRegOpenKey(AccountsKeyHandle, + L"Names", + KEY_READ, + &NamesKeyHandle); + if (NT_SUCCESS(Status)) + { + DataLength = sizeof(ULONG); + Status = SampRegQueryValue(NamesKeyHandle, + Names[i].Buffer, + NULL, + &RelativeId, + &DataLength); + + SampRegCloseKey(NamesKeyHandle); + } + + SampRegCloseKey(AccountsKeyHandle); + } + + /* Return alias account */ + if (NT_SUCCESS(Status) && RelativeId != 0) + { + TRACE("Rid: %lu\n", RelativeId); + RelativeIds->Element[i] = RelativeId; + Use->Element[i] = SidTypeAlias; + MappedCount++; + continue; + } + + /* Lookup groups */ + Status = SampRegOpenKey(DomainObject->KeyHandle, + L"Groups", + KEY_READ, + &AccountsKeyHandle); + if (NT_SUCCESS(Status)) + { + Status = SampRegOpenKey(AccountsKeyHandle, + L"Names", + KEY_READ, + &NamesKeyHandle); + if (NT_SUCCESS(Status)) + { + DataLength = sizeof(ULONG); + Status = SampRegQueryValue(NamesKeyHandle, + Names[i].Buffer, + NULL, + &RelativeId, + &DataLength); + + SampRegCloseKey(NamesKeyHandle); + } + + SampRegCloseKey(AccountsKeyHandle); + } + + /* Return group account */ + if (NT_SUCCESS(Status) && RelativeId != 0) + { + TRACE("Rid: %lu\n", RelativeId); + RelativeIds->Element[i] = RelativeId; + Use->Element[i] = SidTypeGroup; + MappedCount++; + continue; + } + + /* Lookup users */ + Status = SampRegOpenKey(DomainObject->KeyHandle, + L"Users", + KEY_READ, + &AccountsKeyHandle); + if (NT_SUCCESS(Status)) + { + Status = SampRegOpenKey(AccountsKeyHandle, + L"Names", + KEY_READ, + &NamesKeyHandle); + if (NT_SUCCESS(Status)) + { + DataLength = sizeof(ULONG); + Status = SampRegQueryValue(NamesKeyHandle, + Names[i].Buffer, + NULL, + &RelativeId, + &DataLength); + + SampRegCloseKey(NamesKeyHandle); + } + + SampRegCloseKey(AccountsKeyHandle); + } + + /* Return user account */ + if (NT_SUCCESS(Status) && RelativeId != 0) + { + TRACE("Rid: %lu\n", RelativeId); + RelativeIds->Element[i] = RelativeId; + Use->Element[i] = SidTypeUser; + MappedCount++; + continue; + } + + /* Return unknown account */ + RelativeIds->Element[i] = 0; + Use->Element[i] = SidTypeUnknown; + } + +done: + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) + Status = STATUS_SUCCESS; + + if (NT_SUCCESS(Status)) + { + if (MappedCount == 0) + Status = STATUS_NONE_MAPPED; + else if (MappedCount < Count) + Status = STATUS_SOME_NOT_MAPPED; + } + else + { + if (RelativeIds->Element != NULL) + { + midl_user_free(RelativeIds->Element); + RelativeIds->Element = NULL; + } + + RelativeIds->Count = 0; + + if (Use->Element != NULL) + { + midl_user_free(Use->Element); + Use->Element = NULL; + } + + Use->Count = 0; + } + + return Status; } + /* Function 18 */ NTSTATUS NTAPI @@ -5546,6 +5743,7 @@ SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle, return STATUS_NOT_IMPLEMENTED; } + /* Function 50 */ NTSTATUS NTAPI @@ -5557,8 +5755,260 @@ SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle, OUT unsigned long *GrantedAccess, OUT unsigned long *RelativeId) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L""); + SAM_DOMAIN_FIXED_DATA FixedDomainData; + SAM_USER_FIXED_DATA FixedUserData; + PSAM_DB_OBJECT DomainObject; + PSAM_DB_OBJECT UserObject; + ULONG ulSize; + ULONG ulRid; + WCHAR szRid[9]; + NTSTATUS Status; + + TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n", + DomainHandle, Name, DesiredAccess, UserHandle, RelativeId); + + if (Name == NULL || + Name->Length == 0 || + Name->Buffer == NULL || + UserHandle == NULL || + RelativeId == NULL) + return STATUS_INVALID_PARAMETER; + + /* Check for valid account type */ + if (AccountType != USER_NORMAL_ACCOUNT && + AccountType != USER_WORKSTATION_TRUST_ACCOUNT && + AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT && + AccountType != USER_SERVER_TRUST_ACCOUNT && + AccountType != USER_TEMP_DUPLICATE_ACCOUNT) + return STATUS_INVALID_PARAMETER; + + /* Validate the domain handle */ + Status = SampValidateDbObject(DomainHandle, + SamDbDomainObject, + DOMAIN_CREATE_USER, + &DomainObject); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Check if the user name already exists in the domain */ + Status = SampCheckAccountNameInDomain(DomainObject, + Name->Buffer); + if (!NT_SUCCESS(Status)) + { + TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n", + Name->Buffer, Status); + return Status; + } + + /* Get the fixed domain attributes */ + ulSize = sizeof(SAM_DOMAIN_FIXED_DATA); + Status = SampGetObjectAttribute(DomainObject, + L"F", + NULL, + (PVOID)&FixedDomainData, + &ulSize); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Increment the NextRid attribute */ + ulRid = FixedDomainData.NextRid; + FixedDomainData.NextRid++; + + /* Store the fixed domain attributes */ + Status = SampSetObjectAttribute(DomainObject, + L"F", + REG_BINARY, + &FixedDomainData, + ulSize); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + TRACE("RID: %lx\n", ulRid); + + /* Convert the RID into a string (hex) */ + swprintf(szRid, L"%08lX", ulRid); + + /* Create the user object */ + Status = SampCreateDbObject(DomainObject, + L"Users", + szRid, + SamDbUserObject, + DesiredAccess, + &UserObject); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Add the account name for the user object */ + Status = SampSetAccountNameInDomain(DomainObject, + L"Users", + Name->Buffer, + ulRid); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Initialize fixed user data */ + memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA)); + FixedUserData.Version = 1; + FixedUserData.LastLogon.QuadPart = 0; + FixedUserData.LastLogoff.QuadPart = 0; + FixedUserData.PasswordLastSet.QuadPart = 0; + FixedUserData.AccountExpires.LowPart = MAXULONG; + FixedUserData.AccountExpires.HighPart = MAXLONG; + FixedUserData.LastBadPasswordTime.QuadPart = 0; + FixedUserData.UserId = ulRid; + FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS; + FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED | + USER_PASSWORD_NOT_REQUIRED | + AccountType; + + /* 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", + REG_SZ, + (LPVOID)Name->Buffer, + Name->MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the FullName attribute */ + Status = SampSetObjectAttribute(UserObject, + L"FullName", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the HomeDirectory attribute */ + Status = SampSetObjectAttribute(UserObject, + L"HomeDirectory", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the HomeDirectoryDrive attribute */ + Status = SampSetObjectAttribute(UserObject, + L"HomeDirectoryDrive", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the ScriptPath attribute */ + Status = SampSetObjectAttribute(UserObject, + L"ScriptPath", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the ProfilePath attribute */ + Status = SampSetObjectAttribute(UserObject, + L"ProfilePath", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the AdminComment attribute */ + Status = SampSetObjectAttribute(UserObject, + L"AdminComment", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the UserComment attribute */ + Status = SampSetObjectAttribute(UserObject, + L"UserComment", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the WorkStations attribute */ + Status = SampSetObjectAttribute(UserObject, + L"WorkStations", + REG_SZ, + EmptyString.Buffer, + EmptyString.MaximumLength); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* FIXME: Set default user attributes */ + + if (NT_SUCCESS(Status)) + { + *UserHandle = (SAMPR_HANDLE)UserObject; + *RelativeId = ulRid; + *GrantedAccess = UserObject->Access; + } + + TRACE("returns with status 0x%08lx\n", Status); + + return Status; } /* Function 51 */ diff --git a/reactos/include/ddk/ntsam.h b/reactos/include/ddk/ntsam.h index e992b02e27e..2e04ed85740 100644 --- a/reactos/include/ddk/ntsam.h +++ b/reactos/include/ddk/ntsam.h @@ -349,6 +349,16 @@ SamCreateGroupInDomain(IN SAM_HANDLE DomainHandle, OUT PSAM_HANDLE GroupHandle, OUT PULONG RelativeId); +NTSTATUS +NTAPI +SamCreateUser2InDomain(IN SAM_HANDLE DomainHandle, + IN PUNICODE_STRING AccountName, + IN ULONG AccountType, + IN ACCESS_MASK DesiredAccess, + OUT PSAM_HANDLE UserHandle, + OUT PULONG GrantedAccess, + OUT PULONG RelativeId); + NTSTATUS NTAPI SamCreateUserInDomain(IN SAM_HANDLE DomainHandle,