diff --git a/reactos/dll/win32/samlib/samlib.c b/reactos/dll/win32/samlib/samlib.c index 2ddae0f7c30..0f4146b3025 100644 --- a/reactos/dll/win32/samlib/samlib.c +++ b/reactos/dll/win32/samlib/samlib.c @@ -431,6 +431,36 @@ SamConnect(IN OUT PUNICODE_STRING ServerName, return Status; } +NTSTATUS +NTAPI +SamCreateUserInDomain(IN SAM_HANDLE DomainHandle, + IN PUNICODE_STRING AccountName, + IN ACCESS_MASK DesiredAccess, + OUT PSAM_HANDLE UserHandle, + OUT PULONG RelativeId) +{ + NTSTATUS Status; + + TRACE("SamCreateUserInDomain(%p,%p,0x%08x,%p,%p)\n", + DomainHandle, AccountName, DesiredAccess, UserHandle, RelativeId); + + RpcTryExcept + { + Status = SamrCreateUserInDomain((SAMPR_HANDLE)DomainHandle, + (PRPC_UNICODE_STRING)AccountName, + DesiredAccess, + (SAMPR_HANDLE *)UserHandle, + RelativeId); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + Status = I_RpcMapWin32Status(RpcExceptionCode()); + } + RpcEndExcept; + + return Status; +} + NTSTATUS NTAPI SamOpenDomain(IN SAM_HANDLE ServerHandle, diff --git a/reactos/dll/win32/samlib/samlib.spec b/reactos/dll/win32/samlib/samlib.spec index e08538f7c1f..25cb6e2b498 100644 --- a/reactos/dll/win32/samlib/samlib.spec +++ b/reactos/dll/win32/samlib/samlib.spec @@ -10,7 +10,7 @@ @ stub SamCreateAliasInDomain @ stub SamCreateGroupInDomain @ stub SamCreateUser2InDomain -@ stub SamCreateUserInDomain +@ stdcall SamCreateUserInDomain(ptr ptr long ptr ptr) @ stub SamDeleteAlias @ stub SamDeleteGroup @ stub SamDeleteUser diff --git a/reactos/dll/win32/samsrv/database.c b/reactos/dll/win32/samsrv/database.c index 28a88e1dcdb..9810bbeec33 100644 --- a/reactos/dll/win32/samsrv/database.c +++ b/reactos/dll/win32/samsrv/database.c @@ -602,6 +602,151 @@ SampCloseDbObject(PSAM_DB_OBJECT DbObject) } +NTSTATUS +SampSetDbObjectNameAlias(IN PSAM_DB_OBJECT DomainObject, + IN LPCWSTR lpContainerName, + IN LPCWSTR lpAliasName, + IN ULONG ulAliasValue) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName; + UNICODE_STRING ValueName; + HANDLE ContainerKeyHandle = NULL; + HANDLE NamesKeyHandle = NULL; + NTSTATUS Status; + + /* Open the container key */ + RtlInitUnicodeString(&KeyName, lpContainerName); + + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + DomainObject->KeyHandle, + NULL); + + Status = NtOpenKey(&ContainerKeyHandle, + KEY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + return Status; + + /* Open the 'Names' key */ + RtlInitUnicodeString(&KeyName, L"Names"); + + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + ContainerKeyHandle, + NULL); + + Status = NtOpenKey(&NamesKeyHandle, + KEY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + goto done; + + /* Set the alias value */ + RtlInitUnicodeString(&ValueName, lpAliasName); + + Status = NtSetValueKey(NamesKeyHandle, + &ValueName, + 0, + REG_DWORD, + (LPVOID)&ulAliasValue, + sizeof(ULONG)); + +done: + if (NamesKeyHandle) + NtClose(NamesKeyHandle); + + if (ContainerKeyHandle) + NtClose(ContainerKeyHandle); + + return Status; +} + + +NTSTATUS +SampCheckDbObjectNameAlias(IN PSAM_DB_OBJECT DomainObject, + IN LPCWSTR lpContainerName, + IN LPCWSTR lpAliasName, + OUT PBOOL bAliasExists) +{ + PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName; + UNICODE_STRING ValueName; + HANDLE ContainerKeyHandle = NULL; + HANDLE NamesKeyHandle = NULL; + ULONG BufferLength = sizeof(ULONG); + NTSTATUS Status; + + /* Open the container key */ + RtlInitUnicodeString(&KeyName, lpContainerName); + + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + DomainObject->KeyHandle, + NULL); + + Status = NtOpenKey(&ContainerKeyHandle, + KEY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + return Status; + + /* Open the 'Names' key */ + RtlInitUnicodeString(&KeyName, L"Names"); + + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + ContainerKeyHandle, + NULL); + + Status = NtOpenKey(&NamesKeyHandle, + KEY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + goto done; + + /* Get the alias value */ + RtlInitUnicodeString(&ValueName, lpAliasName); + + BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); + + /* Allocate memory for the value */ + ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); + if (ValueInfo == NULL) + return STATUS_NO_MEMORY; + + /* Query the value */ + Status = ZwQueryValueKey(NamesKeyHandle, + &ValueName, + KeyValuePartialInformation, + ValueInfo, + BufferLength, + &BufferLength); + + *bAliasExists = (Status != STATUS_OBJECT_NAME_NOT_FOUND); + + Status = STATUS_SUCCESS; + + /* Free the memory and return status */ + RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo); + +done: + if (NamesKeyHandle) + NtClose(NamesKeyHandle); + + if (ContainerKeyHandle) + NtClose(ContainerKeyHandle); + + return Status; +} + + NTSTATUS SampSetObjectAttribute(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName, diff --git a/reactos/dll/win32/samsrv/samrpc.c b/reactos/dll/win32/samsrv/samrpc.c index 431c55c90c1..8e19334829f 100644 --- a/reactos/dll/win32/samsrv/samrpc.c +++ b/reactos/dll/win32/samsrv/samrpc.c @@ -193,6 +193,7 @@ SamrOpenDomain(IN SAMPR_HANDLE ServerHandle, TRACE("SamrOpenDomain(%p %lx %p %p)\n", ServerHandle, DesiredAccess, DomainId, DomainHandle); + /* Validate the server handle */ Status = SampValidateDbObject(ServerHandle, SamDbServerObject, SAM_SERVER_LOOKUP_DOMAIN, @@ -216,7 +217,7 @@ SamrOpenDomain(IN SAMPR_HANDLE ServerHandle, Status = SampOpenDbObject(ServerObject, L"Domains", L"Builtin", - SamDbServerObject, + SamDbDomainObject, DesiredAccess, &DomainObject); } @@ -231,7 +232,7 @@ SamrOpenDomain(IN SAMPR_HANDLE ServerHandle, Status = SampOpenDbObject(ServerObject, L"Domains", L"Account", - SamDbServerObject, + SamDbDomainObject, DesiredAccess, &DomainObject); } @@ -306,8 +307,116 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle, OUT SAMPR_HANDLE *UserHandle, OUT unsigned long *RelativeId) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PSAM_DB_OBJECT DomainObject; + PSAM_DB_OBJECT UserObject; + ULONG ulSize; + ULONG ulRid; + WCHAR szRid[9]; + BOOL bAliasExists = FALSE; + NTSTATUS Status; + + TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n", + DomainHandle, Name, DesiredAccess, UserHandle, RelativeId); + + /* 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; + } + + /* Get the NextRID attribute */ + ulSize = sizeof(ULONG); + Status = SampGetObjectAttribute(DomainObject, + L"NextRID", + NULL, + (LPVOID)&ulRid, + &ulSize); + if (!NT_SUCCESS(Status)) + ulRid = DOMAIN_USER_RID_MAX; + + TRACE("RID: %lx\n", ulRid); + + /* Convert the RID into a string (hex) */ + _ultow(ulRid, szRid, 16); + + /* Check whether the user name is already in use */ + Status = SampCheckDbObjectNameAlias(DomainObject, + L"Users", + Name->Buffer, + &bAliasExists); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + if (bAliasExists) + { + TRACE("The user account %S already exists!\n", Name->Buffer); + return STATUS_USER_EXISTS; + } + + /* 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 name alias for the user object */ + Status = SampSetDbObjectNameAlias(DomainObject, + L"Users", + Name->Buffer, + ulRid); + if (!NT_SUCCESS(Status)) + { + TRACE("failed with status 0x%08lx\n", Status); + return Status; + } + + /* Set the account name attribute */ + Status = SampSetObjectAttribute(UserObject, + L"AccountName", + REG_SZ, + (LPVOID)Name->Buffer, + Name->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; + } + + /* Increment the NextRID attribute */ + ulRid++; + ulSize = sizeof(ULONG); + SampSetObjectAttribute(DomainObject, + L"NextRID", + REG_DWORD, + (LPVOID)&ulRid, + ulSize); + + TRACE("returns with status 0x%08lx\n", Status); + + return Status; } /* Function 13 */ diff --git a/reactos/dll/win32/samsrv/samsrv.h b/reactos/dll/win32/samsrv/samsrv.h index 795b4c310ab..af33771808e 100644 --- a/reactos/dll/win32/samsrv/samsrv.h +++ b/reactos/dll/win32/samsrv/samsrv.h @@ -7,6 +7,7 @@ * PROGRAMMERS: Eric Kohl */ +#include #define WIN32_NO_STATUS #include #define NTOS_MODE_USER @@ -75,6 +76,18 @@ SampValidateDbObject(SAMPR_HANDLE Handle, NTSTATUS SampCloseDbObject(PSAM_DB_OBJECT DbObject); +NTSTATUS +SampSetDbObjectNameAlias(IN PSAM_DB_OBJECT DomainObject, + IN LPCWSTR lpContainerName, + IN LPCWSTR lpAliasName, + IN DWORD dwAliasValue); + +NTSTATUS +SampCheckDbObjectNameAlias(IN PSAM_DB_OBJECT DomainObject, + IN LPCWSTR lpContainerName, + IN LPCWSTR lpAliasName, + OUT PBOOL bAliasExists); + NTSTATUS SampSetObjectAttribute(PSAM_DB_OBJECT DbObject, LPWSTR AttributeName, diff --git a/reactos/include/ddk/ntsam.h b/reactos/include/ddk/ntsam.h index f19688d1808..fec2f53c01e 100644 --- a/reactos/include/ddk/ntsam.h +++ b/reactos/include/ddk/ntsam.h @@ -6,6 +6,18 @@ extern "C" { #endif +#define DOMAIN_READ_PASSWORD_PARAMETERS 1 +#define DOMAIN_WRITE_PASSWORD_PARAMS 2 +#define DOMAIN_READ_OTHER_PARAMETERS 4 +#define DOMAIN_WRITE_OTHER_PARAMETERS 8 +#define DOMAIN_CREATE_USER 16 +#define DOMAIN_CREATE_GROUP 32 +#define DOMAIN_CREATE_ALIAS 64 +#define DOMAIN_GET_ALIAS_MEMBERSHIP 128 +#define DOMAIN_LIST_ACCOUNTS 256 +#define DOMAIN_LOOKUP 512 +#define DOMAIN_ADMINISTER_SERVER 1024 + #define SAM_SERVER_CONNECT 1 #define SAM_SERVER_SHUTDOWN 2 #define SAM_SERVER_INITIALIZE 4