* PROGRAMMERS: Eric Kohl
*/
-/* INCLUDES ****************************************************************/
+/* INCLUDES ******************************************************************/
#include "samsrv.h"
WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
-/* GLOBALS ********************************************************************/
+/* GLOBALS *******************************************************************/
static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
-/* FUNCTIONS ***************************************************************/
+
+/* FUNCTIONS *****************************************************************/
VOID
SampStartRpcServer(VOID)
OUT SAMPR_HANDLE *GroupHandle,
OUT unsigned long *RelativeId)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/* Function 10 */
-NTSTATUS
-NTAPI
-SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
- IN OUT unsigned long *EnumerationContext,
- OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
- IN unsigned long PreferedMaximumLength,
- OUT unsigned long *CountReturned)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/* Function 12 */
-NTSTATUS
-NTAPI
-SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
- IN PRPC_UNICODE_STRING Name,
- IN ACCESS_MASK DesiredAccess,
- OUT SAMPR_HANDLE *UserHandle,
- OUT unsigned long *RelativeId)
-{
+ UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
SAM_DOMAIN_FIXED_DATA FixedDomainData;
- SAM_USER_FIXED_DATA FixedUserData;
+ SAM_GROUP_FIXED_DATA FixedGroupData;
PSAM_DB_OBJECT DomainObject;
- PSAM_DB_OBJECT UserObject;
+ PSAM_DB_OBJECT GroupObject;
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);
+ TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
+ DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
/* Validate the domain handle */
Status = SampValidateDbObject(DomainHandle,
SamDbDomainObject,
- DOMAIN_CREATE_USER,
+ DOMAIN_CREATE_GROUP,
&DomainObject);
if (!NT_SUCCESS(Status))
{
return Status;
}
+ /* Check if the group name already exists in the domain */
+ Status = SampCheckAccountNameInDomain(DomainObject,
+ Name->Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Group 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,
/* Convert the RID into a string (hex) */
swprintf(szRid, L"%08lX", ulRid);
- /* 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 */
+ /* Create the group object */
Status = SampCreateDbObject(DomainObject,
- L"Users",
+ L"Groups",
szRid,
- SamDbUserObject,
+ SamDbGroupObject,
DesiredAccess,
- &UserObject);
+ &GroupObject);
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);
+ /* Add the account name of the user object */
+ Status = SampSetAccountNameInDomain(DomainObject,
+ L"Groups",
+ Name->Buffer,
+ ulRid);
if (!NT_SUCCESS(Status))
{
TRACE("failed with status 0x%08lx\n", Status);
}
/* Initialize fixed user data */
- memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
- FixedUserData.Version = 1;
+ memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
+ FixedGroupData.Version = 1;
- FixedUserData.UserId = ulRid;
+ FixedGroupData.GroupId = ulRid;
/* Set fixed user data attribute */
- Status = SampSetObjectAttribute(UserObject,
+ Status = SampSetObjectAttribute(GroupObject,
L"F",
REG_BINARY,
- (LPVOID)&FixedUserData,
- sizeof(SAM_USER_FIXED_DATA));
+ (LPVOID)&FixedGroupData,
+ sizeof(SAM_GROUP_FIXED_DATA));
if (!NT_SUCCESS(Status))
{
TRACE("failed with status 0x%08lx\n", Status);
return Status;
}
- /* Set the name attribute */
- Status = SampSetObjectAttribute(UserObject,
+ /* Set the Name attribute */
+ Status = SampSetObjectAttribute(GroupObject,
L"Name",
REG_SZ,
(LPVOID)Name->Buffer,
return Status;
}
- /* FIXME: Set default user attributes */
-
- if (NT_SUCCESS(Status))
- {
- *UserHandle = (SAMPR_HANDLE)UserObject;
- *RelativeId = ulRid;
- }
-
- TRACE("returns with status 0x%08lx\n", Status);
-
- return Status;
-}
-
-/* Function 13 */
-NTSTATUS
-NTAPI
-SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
- IN OUT unsigned long *EnumerationContext,
- IN unsigned long UserAccountControl,
- OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
- IN unsigned long PreferedMaximumLength,
- OUT unsigned long *CountReturned)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/* Function 14 */
-NTSTATUS
-NTAPI
-SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
- IN PRPC_UNICODE_STRING AccountName,
- IN ACCESS_MASK DesiredAccess,
- OUT SAMPR_HANDLE *AliasHandle,
- OUT unsigned long *RelativeId)
-{
- SAM_DOMAIN_FIXED_DATA FixedDomainData;
- PSAM_DB_OBJECT DomainObject;
- PSAM_DB_OBJECT AliasObject;
- UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
- ULONG ulSize;
- ULONG ulRid;
- WCHAR szRid[9];
- BOOL bAliasExists = FALSE;
- NTSTATUS Status;
-
- TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
- DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
-
- /* Validate the domain handle */
- Status = SampValidateDbObject(DomainHandle,
- SamDbDomainObject,
- DOMAIN_CREATE_ALIAS,
- &DomainObject);
- if (!NT_SUCCESS(Status))
- {
- TRACE("failed with status 0x%08lx\n", 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);
-
- /* Check whether the user name is already in use */
- Status = SampCheckDbObjectNameAlias(DomainObject,
- L"Aliases",
- AccountName->Buffer,
- &bAliasExists);
- if (!NT_SUCCESS(Status))
- {
- TRACE("failed with status 0x%08lx\n", Status);
- return Status;
- }
-
- if (bAliasExists)
- {
- TRACE("The alias account %S already exists!\n", AccountName->Buffer);
- return STATUS_ALIAS_EXISTS;
- }
-
- /* Create the user object */
- Status = SampCreateDbObject(DomainObject,
- L"Aliases",
- szRid,
- SamDbAliasObject,
- DesiredAccess,
- &AliasObject);
- 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"Aliases",
- AccountName->Buffer,
- ulRid);
- if (!NT_SUCCESS(Status))
- {
- TRACE("failed with status 0x%08lx\n", Status);
- return Status;
- }
-
- /* Set the Name attribute */
- Status = SampSetObjectAttribute(AliasObject,
- L"Name",
- REG_SZ,
- (LPVOID)AccountName->Buffer,
- AccountName->MaximumLength);
- if (!NT_SUCCESS(Status))
- {
- TRACE("failed with status 0x%08lx\n", Status);
- return Status;
- }
-
- /* Set the Description attribute */
- Status = SampSetObjectAttribute(AliasObject,
- L"Description",
+ /* Set the AdminComment attribute */
+ Status = SampSetObjectAttribute(GroupObject,
+ L"AdminComment",
REG_SZ,
EmptyString.Buffer,
EmptyString.MaximumLength);
if (NT_SUCCESS(Status))
{
- *AliasHandle = (SAMPR_HANDLE)AliasObject;
+ *GroupHandle = (SAMPR_HANDLE)GroupObject;
*RelativeId = ulRid;
}
return Status;
}
-/* Function 15 */
+
+/* Function 11 */
NTSTATUS
NTAPI
-SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
- IN OUT unsigned long *EnumerationContext,
- OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
- IN unsigned long PreferedMaximumLength,
- OUT unsigned long *CountReturned)
+SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN OUT unsigned long *EnumerationContext,
+ OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
+ IN unsigned long PreferedMaximumLength,
+ OUT unsigned long *CountReturned)
{
PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
PSAM_DB_OBJECT DomainObject;
- HANDLE AliasesKeyHandle;
- WCHAR AliasKeyName[64];
- HANDLE AliasKeyHandle;
+ HANDLE GroupsKeyHandle = NULL;
+ HANDLE NamesKeyHandle = NULL;
+ WCHAR GroupName[64];
ULONG EnumIndex;
- ULONG EnumCount;
- ULONG RequiredLength;
+ ULONG EnumCount = 0;
+ ULONG RequiredLength = 0;
+ ULONG NameLength;
ULONG DataLength;
+ ULONG Rid;
ULONG i;
BOOLEAN MoreEntries = FALSE;
NTSTATUS Status;
- TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
- DomainHandle, EnumerationContext, Buffer, PreferedMaximumLength,
- CountReturned);
+ TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
+ DomainHandle, EnumerationContext, Buffer,
+ PreferedMaximumLength, CountReturned);
/* Validate the domain handle */
Status = SampValidateDbObject(DomainHandle,
return Status;
Status = SampRegOpenKey(DomainObject->KeyHandle,
- L"Aliases",
+ L"Groups",
KEY_READ,
- &AliasesKeyHandle);
+ &GroupsKeyHandle);
if (!NT_SUCCESS(Status))
return Status;
+ Status = SampRegOpenKey(GroupsKeyHandle,
+ L"Names",
+ KEY_READ,
+ &NamesKeyHandle);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
TRACE("Part 1\n");
EnumIndex = *EnumerationContext;
- EnumCount = 0;
- RequiredLength = 0;
while (TRUE)
{
- Status = SampRegEnumerateSubKey(AliasesKeyHandle,
- EnumIndex,
- 64 * sizeof(WCHAR),
- AliasKeyName);
+ NameLength = 64 * sizeof(WCHAR);
+ Status = SampRegEnumerateValue(NamesKeyHandle,
+ EnumIndex,
+ GroupName,
+ &NameLength,
+ NULL,
+ NULL,
+ NULL);
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_NO_MORE_ENTRIES)
}
TRACE("EnumIndex: %lu\n", EnumIndex);
- TRACE("Alias key name: %S\n", AliasKeyName);
+ TRACE("Group name: %S\n", GroupName);
+ TRACE("Name length: %lu\n", NameLength);
- Status = SampRegOpenKey(AliasesKeyHandle,
- AliasKeyName,
- KEY_READ,
- &AliasKeyHandle);
- TRACE("SampRegOpenKey returned %08lX\n", Status);
- if (NT_SUCCESS(Status))
+ if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
{
- DataLength = 0;
- Status = SampRegQueryValue(AliasKeyHandle,
- L"Name",
- NULL,
- NULL,
- &DataLength);
-
- NtClose(AliasKeyHandle);
-
- TRACE("SampRegQueryValue returned %08lX\n", Status);
-
- if (NT_SUCCESS(Status))
- {
- TRACE("Data length: %lu\n", DataLength);
-
- if ((RequiredLength + DataLength + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
- {
- MoreEntries = TRUE;
- break;
- }
-
- RequiredLength += (DataLength + sizeof(SAMPR_RID_ENUMERATION));
- EnumCount++;
- }
+ MoreEntries = TRUE;
+ break;
}
+ RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
+ EnumCount++;
+
EnumIndex++;
}
TRACE("EnumCount: %lu\n", EnumCount);
TRACE("RequiredLength: %lu\n", RequiredLength);
- EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
- if (EnumBuffer == NULL)
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
+ if (EnumBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
EnumIndex = *EnumerationContext;
for (i = 0; i < EnumCount; i++, EnumIndex++)
{
- Status = SampRegEnumerateSubKey(AliasesKeyHandle,
- EnumIndex,
- 64 * sizeof(WCHAR),
- AliasKeyName);
+ NameLength = 64 * sizeof(WCHAR);
+ DataLength = sizeof(ULONG);
+ Status = SampRegEnumerateValue(NamesKeyHandle,
+ EnumIndex,
+ GroupName,
+ &NameLength,
+ NULL,
+ &Rid,
+ &DataLength);
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_NO_MORE_ENTRIES)
}
TRACE("EnumIndex: %lu\n", EnumIndex);
- TRACE("Alias key name: %S\n", AliasKeyName);
-
- Status = SampRegOpenKey(AliasesKeyHandle,
- AliasKeyName,
- KEY_READ,
- &AliasKeyHandle);
- TRACE("SampRegOpenKey returned %08lX\n", Status);
- if (NT_SUCCESS(Status))
- {
- DataLength = 0;
- Status = SampRegQueryValue(AliasKeyHandle,
- L"Name",
- NULL,
- NULL,
- &DataLength);
- TRACE("SampRegQueryValue returned %08lX\n", Status);
- if (NT_SUCCESS(Status))
- {
- EnumBuffer->Buffer[i].RelativeId = wcstoul(AliasKeyName, NULL, 16);
-
- EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
- EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
- EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(DataLength);
- if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
- {
- NtClose(AliasKeyHandle);
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto done;
- }
+ TRACE("Group name: %S\n", GroupName);
+ TRACE("Name length: %lu\n", NameLength);
+ TRACE("RID: %lu\n", Rid);
- Status = SampRegQueryValue(AliasKeyHandle,
- L"Name",
- NULL,
- EnumBuffer->Buffer[i].Name.Buffer,
- &DataLength);
- TRACE("SampRegQueryValue returned %08lX\n", Status);
- if (NT_SUCCESS(Status))
- {
- TRACE("Alias name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
- }
- }
+ EnumBuffer->Buffer[i].RelativeId = Rid;
- NtClose(AliasKeyHandle);
+ EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
+ EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
- if (!NT_SUCCESS(Status))
- goto done;
+/* FIXME: Disabled because of bugs in widl and rpcrt4 */
+#if 0
+ EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
+ if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
}
+
+ memcpy(EnumBuffer->Buffer[i].Name.Buffer,
+ GroupName,
+ EnumBuffer->Buffer[i].Name.Length);
+#endif
}
done:
*Buffer = EnumBuffer;
*CountReturned = EnumCount;
}
-
- if (!NT_SUCCESS(Status))
+ else
{
*EnumerationContext = 0;
*Buffer = NULL;
}
}
- NtClose(AliasesKeyHandle);
+ if (NamesKeyHandle != NULL)
+ SampRegCloseKey(NamesKeyHandle);
+
+ if (GroupsKeyHandle != NULL)
+ SampRegCloseKey(GroupsKeyHandle);
if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
Status = STATUS_MORE_ENTRIES;
return Status;
}
-/* Function 16 */
+
+/* Function 12 */
NTSTATUS
NTAPI
-SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
- IN PSAMPR_PSID_ARRAY SidArray,
- OUT PSAMPR_ULONG_ARRAY Membership)
+SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN PRPC_UNICODE_STRING Name,
+ IN ACCESS_MASK DesiredAccess,
+ OUT SAMPR_HANDLE *UserHandle,
+ OUT unsigned long *RelativeId)
{
+ UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
+ SAM_DOMAIN_FIXED_DATA FixedDomainData;
+ SAM_USER_FIXED_DATA FixedUserData;
PSAM_DB_OBJECT DomainObject;
- HANDLE AliasesKeyHandle = NULL;
- HANDLE MembersKeyHandle = NULL;
- HANDLE MemberKeyHandle = NULL;
- LPWSTR MemberSidString = NULL;
- PULONG RidArray = NULL;
- ULONG MaxSidCount = 0;
- ULONG ValueCount;
- ULONG DataLength;
- ULONG i, j;
+ PSAM_DB_OBJECT UserObject;
+ ULONG ulSize;
+ ULONG ulRid;
+ WCHAR szRid[9];
NTSTATUS Status;
- TRACE("SamrGetAliasMembership(%p %p %p)\n",
- DomainHandle, SidArray, Membership);
+ 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;
/* Validate the domain handle */
Status = SampValidateDbObject(DomainHandle,
SamDbDomainObject,
- DOMAIN_LOOKUP,
+ DOMAIN_CREATE_USER,
&DomainObject);
if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
return Status;
+ }
- Status = SampRegOpenKey(DomainObject->KeyHandle,
- L"Aliases",
- KEY_READ,
- &AliasesKeyHandle);
- TRACE("SampRegOpenKey returned %08lX\n", Status);
+ /* Check if the user name already exists in the domain */
+ Status = SampCheckAccountNameInDomain(DomainObject,
+ Name->Buffer);
if (!NT_SUCCESS(Status))
- goto done;
+ {
+ TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
+ Name->Buffer, Status);
+ return Status;
+ }
- Status = SampRegOpenKey(AliasesKeyHandle,
- L"Members",
- KEY_READ,
- &MembersKeyHandle);
- TRACE("SampRegOpenKey returned %08lX\n", 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))
- goto done;
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
- for (i = 0; i < SidArray->Count; i++)
+ /* 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))
{
- ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
-TRACE("Open %S\n", MemberSidString);
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
- Status = SampRegOpenKey(MembersKeyHandle,
- MemberSidString,
- KEY_READ,
- &MemberKeyHandle);
- TRACE("SampRegOpenKey returned %08lX\n", Status);
- if (NT_SUCCESS(Status))
- {
- Status = SampRegQueryKeyInfo(MemberKeyHandle,
- NULL,
- &ValueCount);
- if (NT_SUCCESS(Status))
- {
- TRACE("Found %lu values\n", ValueCount);
- MaxSidCount += ValueCount;
- }
+ TRACE("RID: %lx\n", ulRid);
+ /* Convert the RID into a string (hex) */
+ swprintf(szRid, L"%08lX", ulRid);
- NtClose(MemberKeyHandle);
- }
+ /* 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;
+ }
- LocalFree(MemberSidString);
+ /* 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;
}
- TRACE("Maximum sid count: %lu\n", MaxSidCount);
- RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
- if (RidArray == NULL)
+ /* 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 |
+ USER_NORMAL_ACCOUNT;
+
+ /* Set fixed user data attribute */
+ Status = SampSetObjectAttribute(UserObject,
+ L"F",
+ REG_BINARY,
+ (LPVOID)&FixedUserData,
+ sizeof(SAM_USER_FIXED_DATA));
+ if (!NT_SUCCESS(Status))
{
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto done;
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
}
- for (i = 0; i < SidArray->Count; i++)
+ /* Set the Name attribute */
+ Status = SampSetObjectAttribute(UserObject,
+ L"Name",
+ REG_SZ,
+ (LPVOID)Name->Buffer,
+ Name->MaximumLength);
+ if (!NT_SUCCESS(Status))
{
- ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
-TRACE("Open %S\n", MemberSidString);
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
- Status = SampRegOpenKey(MembersKeyHandle,
- MemberSidString,
- KEY_READ,
- &MemberKeyHandle);
- TRACE("SampRegOpenKey returned %08lX\n", Status);
- if (NT_SUCCESS(Status))
- {
- Status = SampRegQueryKeyInfo(MemberKeyHandle,
- NULL,
- &ValueCount);
- if (NT_SUCCESS(Status))
- {
- TRACE("Found %lu values\n", ValueCount);
+ /* 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;
+ }
- for (j = 0; j < ValueCount; j++)
- {
- DataLength = sizeof(ULONG);
- Status = SampRegEnumerateValue(MemberKeyHandle,
- j,
- NULL,
- NULL,
- NULL,
- (PVOID)&RidArray[j],
- &DataLength);
- }
- }
+ /* 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;
+ }
- NtClose(MemberKeyHandle);
- }
+ /* 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;
+ }
+
+ TRACE("returns with status 0x%08lx\n", Status);
+
+ return Status;
+}
+
+
+/* Function 13 */
+NTSTATUS
+NTAPI
+SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN OUT unsigned long *EnumerationContext,
+ IN unsigned long UserAccountControl,
+ OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
+ IN unsigned long PreferedMaximumLength,
+ OUT unsigned long *CountReturned)
+{
+ PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
+ PSAM_DB_OBJECT DomainObject;
+ HANDLE UsersKeyHandle = NULL;
+ HANDLE NamesKeyHandle = NULL;
+ WCHAR UserName[64];
+ ULONG EnumIndex;
+ ULONG EnumCount = 0;
+ ULONG RequiredLength = 0;
+ ULONG NameLength;
+ ULONG DataLength;
+ ULONG Rid;
+ ULONG i;
+ BOOLEAN MoreEntries = FALSE;
+ NTSTATUS Status;
+
+ TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
+ DomainHandle, EnumerationContext, UserAccountControl, Buffer,
+ PreferedMaximumLength, CountReturned);
+
+ /* Validate the domain handle */
+ Status = SampValidateDbObject(DomainHandle,
+ SamDbDomainObject,
+ DOMAIN_LIST_ACCOUNTS,
+ &DomainObject);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ Status = SampRegOpenKey(DomainObject->KeyHandle,
+ L"Users",
+ KEY_READ,
+ &UsersKeyHandle);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ Status = SampRegOpenKey(UsersKeyHandle,
+ L"Names",
+ KEY_READ,
+ &NamesKeyHandle);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ TRACE("Part 1\n");
+
+ EnumIndex = *EnumerationContext;
+
+ while (TRUE)
+ {
+ NameLength = 64 * sizeof(WCHAR);
+ Status = SampRegEnumerateValue(NamesKeyHandle,
+ EnumIndex,
+ UserName,
+ &NameLength,
+ NULL,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status == STATUS_NO_MORE_ENTRIES)
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ TRACE("EnumIndex: %lu\n", EnumIndex);
+ TRACE("User name: %S\n", UserName);
+ TRACE("Name length: %lu\n", NameLength);
+
+ if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
+ {
+ MoreEntries = TRUE;
+ break;
+ }
+
+ RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
+ EnumCount++;
+
+ EnumIndex++;
+ }
+
+ TRACE("EnumCount: %lu\n", EnumCount);
+ TRACE("RequiredLength: %lu\n", RequiredLength);
+
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
+ if (EnumBuffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ EnumBuffer->EntriesRead = EnumCount;
+ if (EnumCount == 0)
+ goto done;
+
+ EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
+ if (EnumBuffer->Buffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ TRACE("Part 2\n");
+
+ EnumIndex = *EnumerationContext;
+ for (i = 0; i < EnumCount; i++, EnumIndex++)
+ {
+ NameLength = 64 * sizeof(WCHAR);
+ DataLength = sizeof(ULONG);
+ Status = SampRegEnumerateValue(NamesKeyHandle,
+ EnumIndex,
+ UserName,
+ &NameLength,
+ NULL,
+ &Rid,
+ &DataLength);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status == STATUS_NO_MORE_ENTRIES)
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ TRACE("EnumIndex: %lu\n", EnumIndex);
+ TRACE("User name: %S\n", UserName);
+ TRACE("Name length: %lu\n", NameLength);
+ TRACE("RID: %lu\n", Rid);
+
+ EnumBuffer->Buffer[i].RelativeId = Rid;
+
+ EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
+ EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
+
+/* FIXME: Disabled because of bugs in widl and rpcrt4 */
+#if 0
+ EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
+ if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ memcpy(EnumBuffer->Buffer[i].Name.Buffer,
+ UserName,
+ EnumBuffer->Buffer[i].Name.Length);
+#endif
+ }
+
+done:
+ if (NT_SUCCESS(Status))
+ {
+ *EnumerationContext += EnumCount;
+ *Buffer = EnumBuffer;
+ *CountReturned = EnumCount;
+ }
+ else
+ {
+ *EnumerationContext = 0;
+ *Buffer = NULL;
+ *CountReturned = 0;
+
+ if (EnumBuffer != NULL)
+ {
+ if (EnumBuffer->Buffer != NULL)
+ {
+ if (EnumBuffer->EntriesRead != 0)
+ {
+ for (i = 0; i < EnumBuffer->EntriesRead; i++)
+ {
+ if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
+ midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
+ }
+ }
+
+ midl_user_free(EnumBuffer->Buffer);
+ }
+
+ midl_user_free(EnumBuffer);
+ }
+ }
+
+ if (NamesKeyHandle != NULL)
+ SampRegCloseKey(NamesKeyHandle);
+
+ if (UsersKeyHandle != NULL)
+ SampRegCloseKey(UsersKeyHandle);
+
+ if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
+ Status = STATUS_MORE_ENTRIES;
+
+ return Status;
+}
+
+
+/* Function 14 */
+NTSTATUS
+NTAPI
+SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN PRPC_UNICODE_STRING AccountName,
+ IN ACCESS_MASK DesiredAccess,
+ OUT SAMPR_HANDLE *AliasHandle,
+ OUT unsigned long *RelativeId)
+{
+ SAM_DOMAIN_FIXED_DATA FixedDomainData;
+ PSAM_DB_OBJECT DomainObject;
+ PSAM_DB_OBJECT AliasObject;
+ UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
+ ULONG ulSize;
+ ULONG ulRid;
+ WCHAR szRid[9];
+ NTSTATUS Status;
+
+ TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
+ DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
+
+ /* Validate the domain handle */
+ Status = SampValidateDbObject(DomainHandle,
+ SamDbDomainObject,
+ DOMAIN_CREATE_ALIAS,
+ &DomainObject);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ /* Check if the alias name already exists in the domain */
+ Status = SampCheckAccountNameInDomain(DomainObject,
+ AccountName->Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
+ AccountName->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 alias object */
+ Status = SampCreateDbObject(DomainObject,
+ L"Aliases",
+ szRid,
+ SamDbAliasObject,
+ DesiredAccess,
+ &AliasObject);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ /* Add the account name for the alias object */
+ Status = SampSetAccountNameInDomain(DomainObject,
+ L"Aliases",
+ AccountName->Buffer,
+ ulRid);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ /* Set the Name attribute */
+ Status = SampSetObjectAttribute(AliasObject,
+ L"Name",
+ REG_SZ,
+ (LPVOID)AccountName->Buffer,
+ AccountName->MaximumLength);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ /* Set the Description attribute */
+ Status = SampSetObjectAttribute(AliasObject,
+ L"Description",
+ REG_SZ,
+ EmptyString.Buffer,
+ EmptyString.MaximumLength);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ *AliasHandle = (SAMPR_HANDLE)AliasObject;
+ *RelativeId = ulRid;
+ }
+
+ TRACE("returns with status 0x%08lx\n", Status);
+
+ return Status;
+}
+
+
+/* Function 15 */
+NTSTATUS
+NTAPI
+SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN OUT unsigned long *EnumerationContext,
+ OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
+ IN unsigned long PreferedMaximumLength,
+ OUT unsigned long *CountReturned)
+{
+ PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
+ PSAM_DB_OBJECT DomainObject;
+ HANDLE AliasesKeyHandle = NULL;
+ HANDLE NamesKeyHandle = NULL;
+ WCHAR AliasName[64];
+ ULONG EnumIndex;
+ ULONG EnumCount = 0;
+ ULONG RequiredLength = 0;
+ ULONG NameLength;
+ ULONG DataLength;
+ ULONG Rid;
+ ULONG i;
+ BOOLEAN MoreEntries = FALSE;
+ NTSTATUS Status;
+
+ TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
+ DomainHandle, EnumerationContext, Buffer,
+ PreferedMaximumLength, CountReturned);
+
+ /* Validate the domain handle */
+ Status = SampValidateDbObject(DomainHandle,
+ SamDbDomainObject,
+ DOMAIN_LIST_ACCOUNTS,
+ &DomainObject);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ Status = SampRegOpenKey(DomainObject->KeyHandle,
+ L"Aliases",
+ KEY_READ,
+ &AliasesKeyHandle);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ Status = SampRegOpenKey(AliasesKeyHandle,
+ L"Names",
+ KEY_READ,
+ &NamesKeyHandle);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ TRACE("Part 1\n");
+
+ EnumIndex = *EnumerationContext;
+
+ while (TRUE)
+ {
+ NameLength = 64 * sizeof(WCHAR);
+ Status = SampRegEnumerateValue(NamesKeyHandle,
+ EnumIndex,
+ AliasName,
+ &NameLength,
+ NULL,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status == STATUS_NO_MORE_ENTRIES)
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ TRACE("EnumIndex: %lu\n", EnumIndex);
+ TRACE("Alias name: %S\n", AliasName);
+ TRACE("Name length: %lu\n", NameLength);
+
+ if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
+ {
+ MoreEntries = TRUE;
+ break;
+ }
+
+ RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
+ EnumCount++;
+
+ EnumIndex++;
+ }
+
+ TRACE("EnumCount: %lu\n", EnumCount);
+ TRACE("RequiredLength: %lu\n", RequiredLength);
+
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
+ if (EnumBuffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ EnumBuffer->EntriesRead = EnumCount;
+ if (EnumCount == 0)
+ goto done;
+
+ EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
+ if (EnumBuffer->Buffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ TRACE("Part 2\n");
+
+ EnumIndex = *EnumerationContext;
+ for (i = 0; i < EnumCount; i++, EnumIndex++)
+ {
+ NameLength = 64 * sizeof(WCHAR);
+ DataLength = sizeof(ULONG);
+ Status = SampRegEnumerateValue(NamesKeyHandle,
+ EnumIndex,
+ AliasName,
+ &NameLength,
+ NULL,
+ &Rid,
+ &DataLength);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status == STATUS_NO_MORE_ENTRIES)
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ TRACE("EnumIndex: %lu\n", EnumIndex);
+ TRACE("Alias name: %S\n", AliasName);
+ TRACE("Name length: %lu\n", NameLength);
+ TRACE("RID: %lu\n", Rid);
+
+ EnumBuffer->Buffer[i].RelativeId = Rid;
+
+ EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
+ EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
+
+/* FIXME: Disabled because of bugs in widl and rpcrt4 */
+#if 0
+ EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
+ if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ memcpy(EnumBuffer->Buffer[i].Name.Buffer,
+ AliasName,
+ EnumBuffer->Buffer[i].Name.Length);
+#endif
+ }
+
+done:
+ if (NT_SUCCESS(Status))
+ {
+ *EnumerationContext += EnumCount;
+ *Buffer = EnumBuffer;
+ *CountReturned = EnumCount;
+ }
+ else
+ {
+ *EnumerationContext = 0;
+ *Buffer = NULL;
+ *CountReturned = 0;
+
+ if (EnumBuffer != NULL)
+ {
+ if (EnumBuffer->Buffer != NULL)
+ {
+ if (EnumBuffer->EntriesRead != 0)
+ {
+ for (i = 0; i < EnumBuffer->EntriesRead; i++)
+ {
+ if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
+ midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
+ }
+ }
+
+ midl_user_free(EnumBuffer->Buffer);
+ }
+
+ midl_user_free(EnumBuffer);
+ }
+ }
+
+ if (NamesKeyHandle != NULL)
+ SampRegCloseKey(NamesKeyHandle);
+
+ if (AliasesKeyHandle != NULL)
+ SampRegCloseKey(AliasesKeyHandle);
+
+ if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
+ Status = STATUS_MORE_ENTRIES;
+
+ return Status;
+}
+
+
+/* Function 16 */
+NTSTATUS
+NTAPI
+SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
+ IN PSAMPR_PSID_ARRAY SidArray,
+ OUT PSAMPR_ULONG_ARRAY Membership)
+{
+ PSAM_DB_OBJECT DomainObject;
+ HANDLE AliasesKeyHandle = NULL;
+ HANDLE MembersKeyHandle = NULL;
+ HANDLE MemberKeyHandle = NULL;
+ LPWSTR MemberSidString = NULL;
+ PULONG RidArray = NULL;
+ ULONG MaxSidCount = 0;
+ ULONG ValueCount;
+ ULONG DataLength;
+ ULONG i, j;
+ NTSTATUS Status;
+
+ TRACE("SamrGetAliasMembership(%p %p %p)\n",
+ DomainHandle, SidArray, Membership);
+
+ /* Validate the domain handle */
+ Status = SampValidateDbObject(DomainHandle,
+ SamDbDomainObject,
+ DOMAIN_LOOKUP,
+ &DomainObject);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ Status = SampRegOpenKey(DomainObject->KeyHandle,
+ L"Aliases",
+ KEY_READ,
+ &AliasesKeyHandle);
+ TRACE("SampRegOpenKey returned %08lX\n", Status);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ Status = SampRegOpenKey(AliasesKeyHandle,
+ L"Members",
+ KEY_READ,
+ &MembersKeyHandle);
+ TRACE("SampRegOpenKey returned %08lX\n", Status);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ for (i = 0; i < SidArray->Count; i++)
+ {
+ ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
+TRACE("Open %S\n", MemberSidString);
+
+ Status = SampRegOpenKey(MembersKeyHandle,
+ MemberSidString,
+ KEY_READ,
+ &MemberKeyHandle);
+ TRACE("SampRegOpenKey returned %08lX\n", Status);
+ if (NT_SUCCESS(Status))
+ {
+ Status = SampRegQueryKeyInfo(MemberKeyHandle,
+ NULL,
+ &ValueCount);
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("Found %lu values\n", ValueCount);
+ MaxSidCount += ValueCount;
+ }
+
+
+ NtClose(MemberKeyHandle);
+ }
+
+ LocalFree(MemberSidString);
+ }
+
+ TRACE("Maximum sid count: %lu\n", MaxSidCount);
+ RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
+ if (RidArray == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ for (i = 0; i < SidArray->Count; i++)
+ {
+ ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
+TRACE("Open %S\n", MemberSidString);
+
+ Status = SampRegOpenKey(MembersKeyHandle,
+ MemberSidString,
+ KEY_READ,
+ &MemberKeyHandle);
+ TRACE("SampRegOpenKey returned %08lX\n", Status);
+ if (NT_SUCCESS(Status))
+ {
+ Status = SampRegQueryKeyInfo(MemberKeyHandle,
+ NULL,
+ &ValueCount);
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("Found %lu values\n", ValueCount);
+
+ for (j = 0; j < ValueCount; j++)
+ {
+ DataLength = sizeof(ULONG);
+ Status = SampRegEnumerateValue(MemberKeyHandle,
+ j,
+ NULL,
+ NULL,
+ NULL,
+ (PVOID)&RidArray[j],
+ &DataLength);
+ }
+ }
+
+ NtClose(MemberKeyHandle);
+ }
+
+ LocalFree(MemberSidString);
+ }
+
+
+done:
+ if (NT_SUCCESS(Status))
+ {
+ Membership->Count = MaxSidCount;
+ Membership->Element = RidArray;
+ }
+ else
+ {
+ if (RidArray != NULL)
+ midl_user_free(RidArray);
+ }
+
+ if (MembersKeyHandle != NULL)
+ NtClose(MembersKeyHandle);
+
+ if (MembersKeyHandle != NULL)
+ NtClose(MembersKeyHandle);
+
+ if (AliasesKeyHandle != NULL)
+ NtClose(AliasesKeyHandle);
+
+ return Status;
+}
+
+
+/* Function 17 */
+NTSTATUS
+NTAPI
+SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN ULONG Count,
+ IN RPC_UNICODE_STRING Names[],
+ OUT PSAMPR_ULONG_ARRAY RelativeIds,
+ OUT PSAMPR_ULONG_ARRAY Use)
+{
+ 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);
+ }
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ break;
+
+ /* 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);
+ }
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ break;
+
+ /* 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);
+ }
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ break;
+
+ /* 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;
+ }
+
+ TRACE("Returned Status %lx\n", Status);
+
+ return Status;
+}
+
+
+/* Function 18 */
+NTSTATUS
+NTAPI
+SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
+ IN ULONG Count,
+ IN ULONG *RelativeIds,
+ OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
+ OUT PSAMPR_ULONG_ARRAY Use)
+{
+ PSAM_DB_OBJECT DomainObject;
+ WCHAR RidString[9];
+ HANDLE AccountsKeyHandle;
+ HANDLE AccountKeyHandle;
+ ULONG MappedCount = 0;
+ ULONG DataLength;
+ ULONG i;
+ NTSTATUS Status;
+
+ TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
+ DomainHandle, Count, RelativeIds, Names, 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;
+ }
+
+ Names->Count = 0;
+ Use->Count = 0;
+
+ if (Count == 0)
+ return STATUS_SUCCESS;
+
+ /* Allocate the names array */
+ Names->Element = midl_user_allocate(Count * sizeof(ULONG));
+ if (Names->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;
+ }
+
+ Names->Count = Count;
+ Use->Count = Count;
+
+ for (i = 0; i < Count; i++)
+ {
+ TRACE("RID: %lu\n", RelativeIds[i]);
+
+ swprintf(RidString, L"%08lx", RelativeIds[i]);
+
+ /* Lookup aliases */
+ Status = SampRegOpenKey(DomainObject->KeyHandle,
+ L"Aliases",
+ KEY_READ,
+ &AccountsKeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ Status = SampRegOpenKey(AccountsKeyHandle,
+ RidString,
+ KEY_READ,
+ &AccountKeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ DataLength = 0;
+ Status = SampRegQueryValue(AccountKeyHandle,
+ L"Name",
+ NULL,
+ NULL,
+ &DataLength);
+ if (NT_SUCCESS(Status))
+ {
+ Names->Element[i].Buffer = midl_user_allocate(DataLength);
+ if (Names->Element[i].Buffer == NULL)
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ if (NT_SUCCESS(Status))
+ {
+ Names->Element[i].MaximumLength = (USHORT)DataLength;
+ Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
+
+ Status = SampRegQueryValue(AccountKeyHandle,
+ L"Name",
+ NULL,
+ Names->Element[i].Buffer,
+ &DataLength);
+ }
+ }
+
+ SampRegCloseKey(AccountKeyHandle);
+ }
+
+ SampRegCloseKey(AccountsKeyHandle);
+ }
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ break;
+
+ /* Return alias account */
+ if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
+ {
+ TRACE("Name: %S\n", Names->Element[i].Buffer);
+ Use->Element[i] = SidTypeAlias;
+ MappedCount++;
+ continue;
+ }
+
+ /* Lookup groups */
+ Status = SampRegOpenKey(DomainObject->KeyHandle,
+ L"Groups",
+ KEY_READ,
+ &AccountsKeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ Status = SampRegOpenKey(AccountsKeyHandle,
+ RidString,
+ KEY_READ,
+ &AccountKeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ DataLength = 0;
+ Status = SampRegQueryValue(AccountKeyHandle,
+ L"Name",
+ NULL,
+ NULL,
+ &DataLength);
+ if (NT_SUCCESS(Status))
+ {
+ Names->Element[i].Buffer = midl_user_allocate(DataLength);
+ if (Names->Element[i].Buffer == NULL)
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ if (NT_SUCCESS(Status))
+ {
+ Names->Element[i].MaximumLength = (USHORT)DataLength;
+ Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
+
+ Status = SampRegQueryValue(AccountKeyHandle,
+ L"Name",
+ NULL,
+ Names->Element[i].Buffer,
+ &DataLength);
+ }
+ }
+
+ SampRegCloseKey(AccountKeyHandle);
+ }
+
+ SampRegCloseKey(AccountsKeyHandle);
+ }
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ break;
+
+ /* Return group account */
+ if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
+ {
+ TRACE("Name: %S\n", Names->Element[i].Buffer);
+ Use->Element[i] = SidTypeGroup;
+ MappedCount++;
+ continue;
+ }
+
+ /* Lookup users */
+ Status = SampRegOpenKey(DomainObject->KeyHandle,
+ L"Users",
+ KEY_READ,
+ &AccountsKeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ Status = SampRegOpenKey(AccountsKeyHandle,
+ RidString,
+ KEY_READ,
+ &AccountKeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ DataLength = 0;
+ Status = SampRegQueryValue(AccountKeyHandle,
+ L"Name",
+ NULL,
+ NULL,
+ &DataLength);
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("DataLength: %lu\n", DataLength);
+
+ Names->Element[i].Buffer = midl_user_allocate(DataLength);
+ if (Names->Element[i].Buffer == NULL)
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ if (NT_SUCCESS(Status))
+ {
+ Names->Element[i].MaximumLength = (USHORT)DataLength;
+ Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
+
+ Status = SampRegQueryValue(AccountKeyHandle,
+ L"Name",
+ NULL,
+ Names->Element[i].Buffer,
+ &DataLength);
+ }
+ }
+
+ SampRegCloseKey(AccountKeyHandle);
+ }
+
+ SampRegCloseKey(AccountsKeyHandle);
+ }
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ break;
+
+ /* Return user account */
+ if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
+ {
+ TRACE("Name: %S\n", Names->Element[i].Buffer);
+ Use->Element[i] = SidTypeUser;
+ MappedCount++;
+ continue;
+ }
+
+ /* Return unknown account */
+ 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 (Names->Element != NULL)
+ {
+ for (i = 0; i < Count; i++)
+ {
+ if (Names->Element[i].Buffer != NULL)
+ midl_user_free(Names->Element[i].Buffer);
+ }
+
+ midl_user_free(Names->Element);
+ Names->Element = NULL;
+ }
+
+ Names->Count = 0;
+
+ if (Use->Element != NULL)
+ {
+ midl_user_free(Use->Element);
+ Use->Element = NULL;
+ }
+
+ Use->Count = 0;
+ }
+
+ return Status;
+}
+
+
+/* Function 19 */
+NTSTATUS
+NTAPI
+SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN unsigned long GroupId,
+ OUT SAMPR_HANDLE *GroupHandle)
+{
+ PSAM_DB_OBJECT DomainObject;
+ PSAM_DB_OBJECT GroupObject;
+ WCHAR szRid[9];
+ NTSTATUS Status;
+
+ TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
+ DomainHandle, DesiredAccess, GroupId, GroupHandle);
+
+ /* 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;
+ }
+
+ /* Convert the RID into a string (hex) */
+ swprintf(szRid, L"%08lX", GroupId);
+
+ /* Create the group object */
+ Status = SampOpenDbObject(DomainObject,
+ L"Groups",
+ szRid,
+ SamDbGroupObject,
+ DesiredAccess,
+ &GroupObject);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ *GroupHandle = (SAMPR_HANDLE)GroupObject;
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
+ PSAMPR_GROUP_INFO_BUFFER *Buffer)
+{
+ PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
+ HANDLE MembersKeyHandle = NULL;
+ SAM_GROUP_FIXED_DATA FixedData;
+ ULONG Length = 0;
+ NTSTATUS Status;
+
+ *Buffer = NULL;
+
+ InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
+ if (InfoBuffer == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Status = SampGetObjectAttributeString(GroupObject,
+ L"Name",
+ &InfoBuffer->General.Name);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ Status = SampGetObjectAttributeString(GroupObject,
+ L"Description",
+ &InfoBuffer->General.AdminComment);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ Length = sizeof(SAM_GROUP_FIXED_DATA);
+ Status = SampGetObjectAttribute(GroupObject,
+ L"F",
+ NULL,
+ (PVOID)&FixedData,
+ &Length);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ InfoBuffer->General.Attributes = FixedData.Attributes;
+
+ /* Open the Members subkey */
+ Status = SampRegOpenKey(GroupObject->KeyHandle,
+ L"Members",
+ KEY_READ,
+ &MembersKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ /* Retrieve the number of members of the alias */
+ Status = SampRegQueryKeyInfo(MembersKeyHandle,
+ NULL,
+ &InfoBuffer->General.MemberCount);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ *Buffer = InfoBuffer;
+
+done:
+ if (MembersKeyHandle != NULL)
+ SampRegCloseKey(MembersKeyHandle);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (InfoBuffer != NULL)
+ {
+ if (InfoBuffer->General.Name.Buffer != NULL)
+ midl_user_free(InfoBuffer->General.Name.Buffer);
+
+ if (InfoBuffer->General.AdminComment.Buffer != NULL)
+ midl_user_free(InfoBuffer->General.AdminComment.Buffer);
+
+ midl_user_free(InfoBuffer);
+ }
+ }
+
+ return Status;
+}
+
+
+static NTSTATUS
+SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
+ PSAMPR_GROUP_INFO_BUFFER *Buffer)
+{
+ PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
+ NTSTATUS Status;
+
+ *Buffer = NULL;
+
+ InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
+ if (InfoBuffer == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Status = SampGetObjectAttributeString(GroupObject,
+ L"Name",
+ &InfoBuffer->Name.Name);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ *Buffer = InfoBuffer;
+
+done:
+ if (!NT_SUCCESS(Status))
+ {
+ if (InfoBuffer != NULL)
+ {
+ if (InfoBuffer->Name.Name.Buffer != NULL)
+ midl_user_free(InfoBuffer->Name.Name.Buffer);
+
+ midl_user_free(InfoBuffer);
+ }
+ }
+
+ return Status;
+}
+
+
+static NTSTATUS
+SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
+ PSAMPR_GROUP_INFO_BUFFER *Buffer)
+{
+ PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
+ SAM_GROUP_FIXED_DATA FixedData;
+ ULONG Length = 0;
+ NTSTATUS Status;
+
+ *Buffer = NULL;
+
+ InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
+ if (InfoBuffer == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Length = sizeof(SAM_GROUP_FIXED_DATA);
+ Status = SampGetObjectAttribute(GroupObject,
+ L"F",
+ NULL,
+ (PVOID)&FixedData,
+ &Length);
+ if (!NT_SUCCESS(Status))
+ goto done;
- LocalFree(MemberSidString);
- }
+ InfoBuffer->Attribute.Attributes = FixedData.Attributes;
+ *Buffer = InfoBuffer;
done:
- if (NT_SUCCESS(Status))
+ if (!NT_SUCCESS(Status))
{
- Membership->Count = MaxSidCount;
- Membership->Element = RidArray;
+ if (InfoBuffer != NULL)
+ {
+ midl_user_free(InfoBuffer);
+ }
}
- else
+
+ return Status;
+}
+
+
+static NTSTATUS
+SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
+ PSAMPR_GROUP_INFO_BUFFER *Buffer)
+{
+ PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
+ NTSTATUS Status;
+
+ *Buffer = NULL;
+
+ InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
+ if (InfoBuffer == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Status = SampGetObjectAttributeString(GroupObject,
+ L"Description",
+ &InfoBuffer->AdminComment.AdminComment);
+ if (!NT_SUCCESS(Status))
{
- if (RidArray != NULL)
- midl_user_free(RidArray);
+ TRACE("Status 0x%08lx\n", Status);
+ goto done;
}
- if (MembersKeyHandle != NULL)
- NtClose(MembersKeyHandle);
+ *Buffer = InfoBuffer;
- if (MembersKeyHandle != NULL)
- NtClose(MembersKeyHandle);
+done:
+ if (!NT_SUCCESS(Status))
+ {
+ if (InfoBuffer != NULL)
+ {
+ if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
+ midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
- if (AliasesKeyHandle != NULL)
- NtClose(AliasesKeyHandle);
+ midl_user_free(InfoBuffer);
+ }
+ }
return Status;
}
-/* Function 17 */
-NTSTATUS
-NTAPI
-SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
- IN unsigned long Count,
- IN RPC_UNICODE_STRING Names[],
- OUT PSAMPR_ULONG_ARRAY RelativeIds,
- OUT PSAMPR_ULONG_ARRAY Use)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/* Function 18 */
-NTSTATUS
-NTAPI
-SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
- IN unsigned long Count,
- IN unsigned long *RelativeIds,
- OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
- OUT PSAMPR_ULONG_ARRAY Use)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/* Function 19 */
-NTSTATUS
-NTAPI
-SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
- IN ACCESS_MASK DesiredAccess,
- IN unsigned long GroupId,
- OUT SAMPR_HANDLE *GroupHandle)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
/* Function 20 */
NTSTATUS
IN GROUP_INFORMATION_CLASS GroupInformationClass,
OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PSAM_DB_OBJECT GroupObject;
+ NTSTATUS Status;
+
+ TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
+ GroupHandle, GroupInformationClass, Buffer);
+
+ /* Validate the group handle */
+ Status = SampValidateDbObject(GroupHandle,
+ SamDbGroupObject,
+ GROUP_READ_INFORMATION,
+ &GroupObject);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ switch (GroupInformationClass)
+ {
+ case GroupGeneralInformation:
+ Status = SampQueryGroupGeneral(GroupObject,
+ Buffer);
+ break;
+
+ case GroupNameInformation:
+ Status = SampQueryGroupName(GroupObject,
+ Buffer);
+ break;
+
+ case GroupAttributeInformation:
+ Status = SampQueryGroupAttribute(GroupObject,
+ Buffer);
+ break;
+
+ case GroupAdminCommentInformation:
+ Status = SampQueryGroupAdminComment(GroupObject,
+ Buffer);
+ break;
+
+ default:
+ Status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return Status;
+}
+
+
+static NTSTATUS
+SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
+ PSAMPR_GROUP_INFO_BUFFER Buffer)
+{
+ SAM_GROUP_FIXED_DATA FixedData;
+ ULONG Length = 0;
+ NTSTATUS Status;
+
+ Length = sizeof(SAM_GROUP_FIXED_DATA);
+ Status = SampGetObjectAttribute(GroupObject,
+ L"F",
+ NULL,
+ (PVOID)&FixedData,
+ &Length);
+ if (!NT_SUCCESS(Status))
+ goto done;
+
+ FixedData.Attributes = Buffer->Attribute.Attributes;
+
+ Status = SampSetObjectAttribute(GroupObject,
+ L"F",
+ REG_BINARY,
+ &FixedData,
+ Length);
+
+done:
+ return Status;
}
+
/* Function 21 */
NTSTATUS
NTAPI
IN GROUP_INFORMATION_CLASS GroupInformationClass,
IN PSAMPR_GROUP_INFO_BUFFER Buffer)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PSAM_DB_OBJECT GroupObject;
+ NTSTATUS Status;
+
+ TRACE("SamrSetInformationGroup(%p %lu %p)\n",
+ GroupHandle, GroupInformationClass, Buffer);
+
+ /* Validate the group handle */
+ Status = SampValidateDbObject(GroupHandle,
+ SamDbGroupObject,
+ GROUP_WRITE_ACCOUNT,
+ &GroupObject);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ switch (GroupInformationClass)
+ {
+ case GroupNameInformation:
+ Status = SampSetObjectAttribute(GroupObject,
+ L"Name",
+ REG_SZ,
+ Buffer->Name.Name.Buffer,
+ Buffer->Name.Name.Length + sizeof(WCHAR));
+ break;
+
+ case GroupAttributeInformation:
+ Status = SampSetGroupAttribute(GroupObject,
+ Buffer);
+ break;
+
+ case GroupAdminCommentInformation:
+ Status = SampSetObjectAttribute(GroupObject,
+ L"Description",
+ REG_SZ,
+ Buffer->AdminComment.AdminComment.Buffer,
+ Buffer->AdminComment.AdminComment.Length + sizeof(WCHAR));
+ break;
+
+ default:
+ Status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return Status;
}
+
/* Function 22 */
NTSTATUS
NTAPI
return STATUS_NOT_IMPLEMENTED;
}
+
/* Function 27 */
NTSTATUS
NTAPI
return Status;
}
+
/* Function 29 */
NTSTATUS
NTAPI
return Status;
}
+
/* Function 30 */
NTSTATUS
NTAPI
return STATUS_NOT_IMPLEMENTED;
}
+
/* Function 31 */
NTSTATUS
NTAPI
TRACE("SamrAddMemberToAlias(%p %p)\n",
AliasHandle, MemberId);
- /* Validate the domain handle */
+ /* Validate the alias handle */
Status = SampValidateDbObject(AliasHandle,
SamDbAliasObject,
ALIAS_ADD_MEMBER,
return Status;
}
+
/* Function 32 */
NTSTATUS
NTAPI
SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
IN PRPC_SID MemberId)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PSAM_DB_OBJECT AliasObject;
+ LPWSTR MemberIdString = NULL;
+ HANDLE MembersKeyHandle = NULL;
+ HANDLE MemberKeyHandle = NULL;
+ ULONG ulValueCount;
+ NTSTATUS Status;
+
+ TRACE("SamrRemoveMemberFromAlias(%p %p)\n",
+ AliasHandle, MemberId);
+
+ /* Validate the alias handle */
+ Status = SampValidateDbObject(AliasHandle,
+ SamDbAliasObject,
+ ALIAS_REMOVE_MEMBER,
+ &AliasObject);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ ConvertSidToStringSidW(MemberId, &MemberIdString);
+ TRACE("Member SID: %S\n", MemberIdString);
+
+ Status = SampRegOpenKey(AliasObject->MembersKeyHandle,
+ MemberIdString,
+ KEY_WRITE | KEY_QUERY_VALUE,
+ &MemberKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegOpenKey failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ Status = SampRegDeleteValue(MemberKeyHandle,
+ AliasObject->Name);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegDeleteValue failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ Status = SampRegQueryKeyInfo(MemberKeyHandle,
+ NULL,
+ &ulValueCount);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ if (ulValueCount == 0)
+ {
+ SampRegCloseKey(MemberKeyHandle);
+ MemberKeyHandle = NULL;
+
+ Status = SampRegDeleteKey(AliasObject->MembersKeyHandle,
+ MemberIdString);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegDeleteKey failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+ }
+
+ Status = SampRegOpenKey(AliasObject->KeyHandle,
+ L"Members",
+ KEY_WRITE | KEY_QUERY_VALUE,
+ &MembersKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegOpenKey failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ Status = SampRegDeleteValue(MembersKeyHandle,
+ MemberIdString);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegDeleteValue failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ Status = SampRegQueryKeyInfo(MembersKeyHandle,
+ NULL,
+ &ulValueCount);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+
+ if (ulValueCount == 0)
+ {
+ SampRegCloseKey(MembersKeyHandle);
+ MembersKeyHandle = NULL;
+
+ Status = SampRegDeleteKey(AliasObject->KeyHandle,
+ L"Members");
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRegDeleteKey failed with status 0x%08lx\n", Status);
+ goto done;
+ }
+ }
+
+done:
+ if (MemberKeyHandle != NULL)
+ SampRegCloseKey(MemberKeyHandle);
+
+ if (MembersKeyHandle != NULL)
+ SampRegCloseKey(MembersKeyHandle);
+
+ if (MemberIdString != NULL)
+ LocalFree(MemberIdString);
+
+ return Status;
}
+
/* Function 33 */
NTSTATUS
NTAPI
return Status;
}
+
/* Function 34 */
NTSTATUS
NTAPI
return STATUS_SUCCESS;
}
+
/* Function 35 */
NTSTATUS
NTAPI
}
-
-
static
NTSTATUS
SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
return STATUS_NOT_IMPLEMENTED;
}
+
/* Function 50 */
NTSTATUS
NTAPI
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 */
NTSTATUS
NTAPI
return STATUS_NOT_IMPLEMENTED;
}
+
/* Function 52 */
NTSTATUS
NTAPI
SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
IN PSAMPR_PSID_ARRAY MembersBuffer)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ ULONG i;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
+ AliasHandle, MembersBuffer);
+
+ for (i = 0; i < MembersBuffer->Count; i++)
+ {
+ Status = SamrAddMemberToAlias(AliasHandle,
+ ((PSID *)MembersBuffer->Sids)[i]);
+
+ if (Status == STATUS_MEMBER_IN_ALIAS)
+ Status = STATUS_SUCCESS;
+
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+
+ return Status;
}
+
/* Function 53 */
NTSTATUS
NTAPI
SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
IN PSAMPR_PSID_ARRAY MembersBuffer)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ ULONG i;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
+ AliasHandle, MembersBuffer);
+
+ for (i = 0; i < MembersBuffer->Count; i++)
+ {
+ Status = SamrRemoveMemberFromAlias(AliasHandle,
+ ((PSID *)MembersBuffer->Sids)[i]);
+
+ if (Status == STATUS_MEMBER_IN_ALIAS)
+ Status = STATUS_SUCCESS;
+
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+
+ return Status;
}
+
/* Function 54 */
NTSTATUS
NTAPI