/*-- Copyright (c) 1992 Microsoft Corporation Module Name: sysdb.c Abstract: System database access routines. Author: Matthew Bradburn (mattbr) 04-Mar-1992 Revision History: --*/ #include "psxsrv.h" #include "psxmsg.h" #include #include #include #include #include #include #define UNICODE #include #include static NTSTATUS PutUserInfo( PSID DomainSid, SAM_HANDLE DomainHandle, ULONG UserId, PCHAR DataDest, OUT int *pLength ); static VOID PutSpecialUserInfo( PUNICODE_STRING Name, PCHAR DataDest, uid_t Uid, OUT int *pLength ); static NTSTATUS PutGroupInfo( PSID DomainSid, SAM_HANDLE DomainHandle, ULONG GroupId, PCHAR DataDest, IN SID_NAME_USE Type, OUT int *pLength ); static VOID PutSpecialGroupInfo( PUNICODE_STRING Name, PCHAR DataDest, gid_t Gid, OUT int *pLength ); static BOOLEAN ConvertPathToPsx( ANSI_STRING *A ); PSID GetSpecialSid( uid_t Uid ); NTSTATUS MySamConnect( IN PSID DomainSid, // NULL if domain unknown OUT PSAM_HANDLE ServerHandle ) { SECURITY_QUALITY_OF_SERVICE SecurityQoS; OBJECT_ATTRIBUTES Obj; NTSTATUS Status; LSA_HANDLE TrustedDomainHandle, PolicyHandle; PTRUSTED_CONTROLLERS_INFO pBuf; ULONG i; SecurityQoS.ImpersonationLevel = SecurityIdentification; SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; SecurityQoS.EffectiveOnly = TRUE; InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL); Obj.SecurityQualityOfService = &SecurityQoS; if (NULL == DomainSid) { Status = SamConnect(NULL, ServerHandle, GENERIC_READ | GENERIC_EXECUTE, &Obj); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't connect to SAM: 0x%x\n", Status)); } return Status; } Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: MySamConnect: LsaOpenPolicy: 0x%x\n", Status)); return Status; } Status = LsaOpenTrustedDomain(PolicyHandle, DomainSid, GENERIC_READ | GENERIC_EXECUTE, &TrustedDomainHandle); if (!NT_SUCCESS(Status)) { LsaClose(PolicyHandle); Status = SamConnect(NULL, ServerHandle, GENERIC_READ | GENERIC_EXECUTE, &Obj); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't connect to SAM: 0x%x\n", Status)); } return Status; } Status = LsaQueryInfoTrustedDomain(TrustedDomainHandle, TrustedControllersInformation, (PVOID *)&pBuf); LsaClose(PolicyHandle); LsaClose(TrustedDomainHandle); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: MySamConnect: LsaQueryInfoTrusted: 0x%x\n", Status)); return Status; } for (i = 0; i < pBuf->Entries; ++i) { if (0 == pBuf->Names[i].Length) { // the null string signifies domain controller unknown continue; } Status = SamConnect(&pBuf->Names[i], ServerHandle, GENERIC_READ | GENERIC_EXECUTE, &Obj); if (NT_SUCCESS(Status)) { // found an acceptable choice LsaFreeMemory(pBuf); return Status; } } LsaFreeMemory(pBuf); // // If there were no acceptable domain controllers, we try the // machine domain // Status = SamConnect(NULL, ServerHandle, GENERIC_EXECUTE, &Obj); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't connect to SAM: 0x%x\n", Status)); } return Status; } NTSTATUS GetMyAccountDomainName( PUNICODE_STRING Domain_U ) { NTSTATUS Status; OBJECT_ATTRIBUTES Obj; SECURITY_QUALITY_OF_SERVICE SecurityQoS; LSA_HANDLE PolicyHandle; PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo; SecurityQoS.ImpersonationLevel = SecurityIdentification; SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; SecurityQoS.EffectiveOnly = TRUE; InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL); Obj.SecurityQualityOfService = &SecurityQoS; Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle); if (!NT_SUCCESS(Status)) { return Status; } Status = LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation, (PVOID *)&AccountDomainInfo); if (!NT_SUCCESS(Status)) { LsaClose(PolicyHandle); return Status; } LsaClose(PolicyHandle); Domain_U->MaximumLength = AccountDomainInfo->DomainName.MaximumLength; Domain_U->Buffer = RtlAllocateHeap(PsxHeap, 0, Domain_U->MaximumLength); if (NULL == Domain_U->Buffer) { return STATUS_NO_MEMORY; } RtlCopyUnicodeString(Domain_U, &AccountDomainInfo->DomainName); LsaFreeMemory(AccountDomainInfo); return STATUS_SUCCESS; } BOOLEAN PsxGetPwUid( IN PPSX_PROCESS p, IN PPSX_API_MSG m ) { NTSTATUS Status; PPSX_GETPWUID_MSG args; PSID DomainSid; SAM_HANDLE ServerHandle = NULL, DomainHandle = NULL; LSA_HANDLE PolicyHandle = NULL; PSID Sid = NULL; OBJECT_ATTRIBUTES Obj; SECURITY_QUALITY_OF_SERVICE SecurityQoS; PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains; PLSA_TRANSLATED_NAME Names; args = &m->u.GetPwUid; if (SE_NULL_POSIX_ID == (args->Uid & 0xFFFF0000)) { // Special case for universal well-known sids and nt // ... well-known sids. Sid = GetSpecialSid(args->Uid); if (NULL == Sid) { m->Error = 1; return TRUE; } goto TryLsa; } DomainSid = GetSidByOffset(args->Uid & 0xFFFF0000); if (NULL == DomainSid) { m->Error = 1; return TRUE; } Status = MySamConnect(DomainSid, &ServerHandle); if (!NT_SUCCESS(Status)) { m->Error = 1; return TRUE; } Status = SamOpenDomain(ServerHandle, GENERIC_EXECUTE, DomainSid, &DomainHandle); if (NT_SUCCESS(Status)) { Status = PutUserInfo(DomainSid, DomainHandle, args->Uid & 0xFFFF, (PCHAR)args->PwBuf, &args->Length); if (NT_SUCCESS(Status)) { goto out; } } // // SAM can't find the name, so we'll try the LSA. // Sid = MakeSid(DomainSid, args->Uid & 0x0000FFFF); TryLsa: SecurityQoS.ImpersonationLevel = SecurityIdentification; SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; SecurityQoS.EffectiveOnly = TRUE; InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL); Obj.SecurityQualityOfService = &SecurityQoS; Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle); if (!NT_SUCCESS(Status)) { m->Error = PsxStatusToErrno(Status); goto out; } Status = LsaLookupSids(PolicyHandle, 1, &Sid, &ReferencedDomains, &Names); if (NT_SUCCESS(Status)) { LsaFreeMemory((PVOID)ReferencedDomains); PutSpecialUserInfo(&Names->Name, (PCHAR)args->PwBuf, args->Uid, &args->Length); LsaFreeMemory((PVOID)Names); } else { UNICODE_STRING U; RtlConvertSidToUnicodeString(&U, Sid, TRUE); PutSpecialUserInfo(&U, (PCHAR)args->PwBuf, args->Uid, &args->Length); RtlFreeUnicodeString(&U); } out: if (NULL != Sid) RtlFreeHeap(PsxHeap, 0, (PVOID)Sid); if (NULL != ServerHandle) SamCloseHandle(ServerHandle); if (NULL != DomainHandle) SamCloseHandle(DomainHandle); if (NULL != PolicyHandle) LsaClose(PolicyHandle); return TRUE; } BOOLEAN PsxGetPwNam( IN PPSX_PROCESS p, IN PPSX_API_MSG m ) { PPSX_GETPWNAM_MSG args; NTSTATUS Status; UNICODE_STRING Name_U, // the user's name in unicode Domain_U; // the name of the account domain ANSI_STRING Name_A; // the user's name in Ansi PULONG pUserId = NULL; // the relative offset for the user SAM_HANDLE ServerHandle = NULL, DomainHandle = NULL; PSID_NAME_USE pUse; PSID DomainSid = NULL; WCHAR ComputerNameBuf[32 + 1]; ULONG Len = 32 + 1; Name_U.Buffer = NULL; args = &m->u.GetPwNam; Status = MySamConnect(DomainSid, &ServerHandle); if (!NT_SUCCESS(Status)) { m->Error = 1; return TRUE; } // // Find the name of the local machine -- we look there for // the name being requested. // if (!GetComputerName(ComputerNameBuf, &Len)) { KdPrint(("PSXSS: GetComputerName: 0x%x\n", GetLastError())); m->Error = 1; goto out; } RtlInitUnicodeString(&Domain_U, ComputerNameBuf); Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U, &DomainSid); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't lookup domain: 0x%x\n", Status)); // // If the "machinename" domain didn't work, try the // account domain. // Status = GetMyAccountDomainName(&Domain_U); if (!NT_SUCCESS(Status)) { m->Error = 1; goto out; } Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U, &DomainSid); RtlFreeHeap(PsxHeap, 0, (PVOID)Domain_U.Buffer); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't lookup acct domain: 0x%x\n", Status)); m->Error = 1; goto out; } } Status = SamOpenDomain(ServerHandle, GENERIC_EXECUTE, DomainSid, &DomainHandle); if (!NT_SUCCESS(Status)) { m->Error = 1; goto out; } RtlInitAnsiString(&Name_A, args->Name); Status = RtlAnsiStringToUnicodeString(&Name_U, &Name_A, TRUE); if (!NT_SUCCESS(Status)) { m->Error = ENOMEM; goto out; } Status = SamLookupNamesInDomain(DomainHandle, 1, &Name_U, &pUserId, &pUse); if (!NT_SUCCESS(Status)) { m->Error = ENOENT; goto out; } // Make sure the name is a user name. if (*pUse != SidTypeUser) { SamFreeMemory(pUse); KdPrint(("PSXSS: Group name is type %d\n", *pUse)); m->Error = 1; goto out; } SamFreeMemory(pUse); Status = PutUserInfo(DomainSid, DomainHandle, *pUserId, (PCHAR)args->PwBuf, &args->Length); if (!NT_SUCCESS(Status)) { m->Error = 1; } out: if (NULL != ServerHandle) { SamCloseHandle(ServerHandle); } if (NULL != DomainHandle) { SamCloseHandle(DomainHandle); } if (NULL != Name_U.Buffer) { RtlFreeUnicodeString(&Name_U); } if (NULL != pUserId) { SamFreeMemory(pUserId); } if (NULL != DomainSid) { SamFreeMemory(DomainSid); } return TRUE; } static VOID PutSpecialUserInfo( PUNICODE_STRING Name, PCHAR DataDest, uid_t Uid, OUT int *pLength ) { PCHAR pch; struct passwd *pwd; ANSI_STRING A; pwd = (struct passwd *)DataDest; pwd->pw_uid = Uid; // Don't know what the gid should be, we use the uid. pwd->pw_gid = Uid; pch = DataDest + sizeof(struct passwd); pwd->pw_name = pch - (ULONG_PTR)DataDest; A.Buffer = pch; A.MaximumLength = NAME_MAX; RtlUnicodeStringToAnsiString(&A, Name, FALSE); pch += strlen(pch) + 1; pwd->pw_dir = pch - (ULONG_PTR)DataDest; strcpy(pch, "/"); pch += strlen(pch) + 1; pwd->pw_shell = pch - (ULONG_PTR)DataDest; strcpy(pch, "noshell"); pch += strlen(pch) + 1; *pLength = (int)((ULONG_PTR)pch - (ULONG_PTR)DataDest); } // // PutUserInfo -- place password database information about the user at // the specified data destination address. // static NTSTATUS PutUserInfo( PSID DomainSid, SAM_HANDLE DomainHandle, ULONG UserId, PCHAR DataDest, int *pLength ) { SAM_HANDLE UserHandle = NULL; PUSER_ACCOUNT_INFORMATION AccountInfo = NULL; PSID Sid; // User Sid ULONG SpaceLeft; struct passwd *pwd; PCHAR pch; NTSTATUS Status; ANSI_STRING A; PCHAR pchPsxDir; Status = SamOpenUser(DomainHandle, GENERIC_READ | GENERIC_EXECUTE, UserId, &UserHandle); if (!NT_SUCCESS(Status)) { goto out; } Status = SamQueryInformationUser(UserHandle, UserAccountInformation, (PVOID *)&AccountInfo); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't query info user: 0x%x\n", Status)); goto out; } pwd = (struct passwd *)DataDest; Sid = MakeSid(DomainSid, AccountInfo->UserId); if (NULL == Sid) { goto out; } pwd->pw_uid = MakePosixId(Sid); RtlFreeHeap(PsxHeap, 0, (PVOID)Sid); Sid = MakeSid(DomainSid, AccountInfo->PrimaryGroupId); if (NULL == Sid) { goto out; } pwd->pw_gid = MakePosixId(Sid); RtlFreeHeap(PsxHeap, 0, (PVOID)Sid); SpaceLeft = ARG_MAX - sizeof(struct passwd); pch = DataDest + sizeof(struct passwd); pwd->pw_name = pch - (ULONG_PTR)DataDest; A.Buffer = pch; A.MaximumLength = (USHORT)SpaceLeft; Status = RtlUnicodeStringToAnsiString(&A, &AccountInfo->UserName, FALSE); if (!NT_SUCCESS(Status)) { goto out; } SpaceLeft -= A.Length; pch = pch + A.Length + 1; pwd->pw_dir = pch - (ULONG_PTR)DataDest; A.Buffer = pch; A.MaximumLength = (USHORT)SpaceLeft; Status = RtlUnicodeStringToAnsiString(&A, &AccountInfo->HomeDirectory, FALSE); if (!NT_SUCCESS(Status)) { goto out; } if (!ConvertPathToPsx(&A)) { goto out; } SpaceLeft -= A.Length; if (SpaceLeft <= strlen("noshell")) { goto out; } pch = pch + A.Length + 1; pwd->pw_shell = pch - (ULONG_PTR)DataDest; strcpy(pch, "noshell"); pch += strlen(pch) + 1; *pLength = (int)((ULONG_PTR)pch - (ULONG_PTR)DataDest); out: if (NULL != UserHandle) { SamCloseHandle(UserHandle); } if (NULL != AccountInfo) { SamFreeMemory(AccountInfo); } return Status; } BOOLEAN PsxGetGrGid( IN PPSX_PROCESS p, IN PPSX_API_MSG m ) { NTSTATUS Status; PPSX_GETGRGID_MSG args; ULONG Gid; PSID DomainSid, GroupSid; SAM_HANDLE ServerHandle = NULL, DomainHandle = NULL; PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL; PLSA_TRANSLATED_NAME Names = NULL; LSA_HANDLE PolicyHandle = NULL; OBJECT_ATTRIBUTES Obj; SECURITY_QUALITY_OF_SERVICE SecurityQoS; PSID Sid = NULL; args = &m->u.GetGrGid; Gid = args->Gid; if (0xFFF == Gid) { UNICODE_STRING U; // // This is a login group, which we'll just translate to // S-1-5-5-0-0 // RtlInitUnicodeString(&U, L"S-1-5-5-0-0"); PutSpecialGroupInfo(&U, (PCHAR)args->GrBuf, Gid, &args->Length); return TRUE; } if (SE_NULL_POSIX_ID == (Gid & 0xFFFF0000)) { // Special case for universal well-known sids and nt // ... well-known sids. Sid = GetSpecialSid(Gid); if (NULL == Sid) { m->Error = 1; return TRUE; } goto TryLsa; } DomainSid = GetSidByOffset(Gid & 0xFFFF0000); if (NULL == DomainSid) { m->Error = 1; return TRUE; } Status = MySamConnect(DomainSid, &ServerHandle); if (!NT_SUCCESS(Status)) { m->Error = 1; return TRUE; } Status = SamOpenDomain(ServerHandle, GENERIC_READ | GENERIC_EXECUTE, DomainSid, &DomainHandle); if (NT_SUCCESS(Status)) { // // Look for a group // Status = PutGroupInfo(DomainSid, DomainHandle, Gid & 0xFFFF, (PCHAR)args->GrBuf, SidTypeGroup, &args->Length); if (NT_SUCCESS(Status)) { goto out; } // // Try again, except look for an alias // Status = PutGroupInfo(DomainSid, DomainHandle, Gid & 0xFFFF, (PCHAR)args->GrBuf, SidTypeAlias, &args->Length); if (NT_SUCCESS(Status)) { goto out; } } // // Give up looking in SAM, ask LSA to identify. // Sid = MakeSid(DomainSid, Gid & 0x0000FFFF); TryLsa: SecurityQoS.ImpersonationLevel = SecurityIdentification; SecurityQoS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; SecurityQoS.EffectiveOnly = TRUE; InitializeObjectAttributes(&Obj, NULL, 0, NULL, NULL); Obj.SecurityQualityOfService = &SecurityQoS; Status = LsaOpenPolicy(NULL, &Obj, GENERIC_EXECUTE, &PolicyHandle); if (!NT_SUCCESS(Status)) { m->Error = PsxStatusToErrno(Status); goto out; } Status = LsaLookupSids(PolicyHandle, 1, &Sid, &ReferencedDomains, &Names); if (NT_SUCCESS(Status)) { LsaFreeMemory((PVOID)ReferencedDomains); PutSpecialGroupInfo(&Names->Name, (PCHAR)args->GrBuf, Gid, &args->Length); LsaFreeMemory((PVOID)Names); goto out; } else { UNICODE_STRING U; RtlConvertSidToUnicodeString(&U, Sid, TRUE); PutSpecialGroupInfo(&U, (PCHAR)args->GrBuf, Gid, &args->Length); RtlFreeUnicodeString(&U); goto out; } out: if (NULL != PolicyHandle) LsaClose(PolicyHandle); if (NULL != ServerHandle) SamCloseHandle(ServerHandle); if (NULL != DomainHandle) SamCloseHandle(DomainHandle); if (NULL != Sid) RtlFreeHeap(PsxHeap, 0, (PVOID)Sid); return TRUE; } BOOLEAN PsxGetGrNam( IN PPSX_PROCESS p, IN PPSX_API_MSG m ) { PPSX_GETGRNAM_MSG args; NTSTATUS Status; UNICODE_STRING Name_U, // the group name in unicode Domain_U; // the name of the account domain ANSI_STRING Name_A; // the group name in Ansi PULONG pGroupId = NULL; // the relative offset for the group SAM_HANDLE ServerHandle = NULL, DomainHandle = NULL; PSID_NAME_USE pUse; PSID DomainSid = NULL, Sid = NULL; WCHAR ComputerNameBuf[32 + 1]; ULONG Len = 32 + 1; SID_NAME_USE Type; Name_U.Buffer = NULL; args = &m->u.GetGrNam; Status = MySamConnect(DomainSid, &ServerHandle); if (!NT_SUCCESS(Status)) { m->Error = 1; return TRUE; } // // Find the name of the local machine -- we look here for // the name being requested. // if (!GetComputerName(ComputerNameBuf, &Len)) { KdPrint(("PSXSS: GetComputerName: 0x%x\n", GetLastError())); m->Error = 1; goto out; } RtlInitUnicodeString(&Domain_U, ComputerNameBuf); Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U, &DomainSid); if (!NT_SUCCESS(Status)) { // // If the "machinename" domain didn't work, try the // account domain. // Status = GetMyAccountDomainName(&Domain_U); if (!NT_SUCCESS(Status)) { m->Error = 1; goto out; } Status = SamLookupDomainInSamServer(ServerHandle, &Domain_U, &DomainSid); RtlFreeHeap(PsxHeap, 0, (PVOID)Domain_U.Buffer); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't lookup acct domain: 0x%x\n", Status)); m->Error = 1; goto out; } } Status = SamOpenDomain(ServerHandle, GENERIC_READ | GENERIC_EXECUTE, DomainSid, &DomainHandle); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't open domain: 0x%x\n", Status)); m->Error = 1; goto out; } RtlInitAnsiString(&Name_A, args->Name); Status = RtlAnsiStringToUnicodeString(&Name_U, &Name_A, TRUE); if (!NT_SUCCESS(Status)) { m->Error = ENOMEM; goto out; } Status = SamLookupNamesInDomain(DomainHandle, 1, &Name_U, &pGroupId, &pUse); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't lookup name: 0x%x\n", Status)); m->Error = 1; goto out; } // Make sure the name is a group name. Type = *pUse; SamFreeMemory(pUse); if (Type != SidTypeGroup && Type != SidTypeAlias) { m->Error = EINVAL; goto out; } Status = PutGroupInfo(DomainSid, DomainHandle, *pGroupId, (PCHAR)args->GrBuf, Type, &args->Length); out: if (NULL != ServerHandle) { SamCloseHandle(ServerHandle); } if (NULL != DomainHandle) { SamCloseHandle(DomainHandle); } if (NULL != Name_U.Buffer) { RtlFreeUnicodeString(&Name_U); } if (NULL != pGroupId) { SamFreeMemory(pGroupId); } if (NULL != DomainSid) { SamFreeMemory(DomainSid); } return TRUE; } static VOID PutSpecialGroupInfo( PUNICODE_STRING Name, PCHAR DataDest, gid_t Gid, OUT int *pLength ) { struct group *grp; PCHAR pch, *ppchMem; ANSI_STRING A; // // The struct group goes at the beginning of the view memory, // followed by the array of member name pointers. // grp = (struct group *)DataDest; ppchMem = (PCHAR *)((PCHAR)DataDest + sizeof(struct group)); grp->gr_mem = (PCHAR *)((PCHAR)ppchMem - (ULONG_PTR)DataDest); grp->gr_gid = Gid; // No members. ppchMem[0] = NULL; pch = (PCHAR)(ppchMem + 1); grp->gr_name = pch - (ULONG_PTR)DataDest; A.Buffer = pch; A.MaximumLength = NAME_MAX; RtlUnicodeStringToAnsiString(&A, Name, FALSE); pch += strlen(pch) + 1; *pLength = (int)((ULONG_PTR)(pch - (ULONG_PTR)DataDest)); } NTSTATUS GetUserNameFromSid( PSID Sid, PANSI_STRING pA) { ULONG SubAuthCount; ULONG RelativeId; PSID DomainSid = NULL; SAM_HANDLE ServerHandle = NULL, DomainHandle = NULL, UserHandle = NULL; PUSER_ACCOUNT_INFORMATION AccountInfo = NULL; NTSTATUS Status = STATUS_SUCCESS; SubAuthCount = *RtlSubAuthorityCountSid(Sid); RelativeId = *RtlSubAuthoritySid(Sid, SubAuthCount - 1); DomainSid = RtlAllocateHeap(PsxHeap, 0, RtlLengthSid(Sid)); if (NULL == DomainSid) { goto out; } Status = RtlCopySid(RtlLengthSid(Sid), DomainSid, Sid); ASSERT(NT_SUCCESS(Status)); --*RtlSubAuthorityCountSid(DomainSid); Status = MySamConnect(DomainSid, &ServerHandle); if (!NT_SUCCESS(Status)) { goto out; } Status = SamOpenDomain(ServerHandle, GENERIC_EXECUTE, DomainSid, &DomainHandle); if (!NT_SUCCESS(Status)) { goto out; } Status = SamOpenUser(DomainHandle, GENERIC_READ | GENERIC_EXECUTE, RelativeId, &UserHandle); if (!NT_SUCCESS(Status)) { goto out; } Status = SamQueryInformationUser(UserHandle, UserAccountInformation, (PVOID *)&AccountInfo); if (!NT_SUCCESS(Status)) { goto out; } Status = RtlUnicodeStringToAnsiString(pA, &AccountInfo->UserName, FALSE); out: if (NULL != DomainSid) RtlFreeHeap(PsxHeap, 0, DomainSid); if (NULL != ServerHandle) SamCloseHandle(ServerHandle); if (NULL != DomainHandle) SamCloseHandle(DomainHandle); if (NULL != UserHandle) SamCloseHandle(UserHandle); if (NULL != AccountInfo) SamFreeMemory(AccountInfo); return Status; } static NTSTATUS PutGroupInfo( PSID DomainSid, SAM_HANDLE DomainHandle, ULONG GroupId, PCHAR DataDest, IN SID_NAME_USE Type, OUT int *pLength ) { ANSI_STRING A; // misc. ansi strings PGROUP_NAME_INFORMATION NameInfo = NULL; ULONG SpaceLeft, count, i; struct group *grp; PCHAR pch, *ppchMem; PSID Sid; NTSTATUS Status; SAM_HANDLE GroupHandle = NULL; PULONG puGroupMem = NULL, // array of group members' relative id's puAttr = NULL; // array of group members' attributes PSID *ppsGroupMem = NULL; // array of alias members' relative id's // // The struct group goes at the beginning of the view memory, // followed by the array of member name pointers. // grp = (struct group *)DataDest; ppchMem = (PCHAR *)((PCHAR)DataDest + sizeof(struct group)); grp->gr_mem = (PCHAR *)((PCHAR)ppchMem - (ULONG_PTR)DataDest); Sid = MakeSid(DomainSid, GroupId); if (NULL == Sid) { goto out; } grp->gr_gid = MakePosixId(Sid); RtlFreeHeap(PsxHeap, 0, Sid); if (SidTypeGroup == Type) { Status = SamOpenGroup(DomainHandle, GENERIC_READ | GENERIC_EXECUTE, GroupId, &GroupHandle); if (!NT_SUCCESS(Status)) { goto out; } Status = SamGetMembersInGroup(GroupHandle, &puGroupMem, &puAttr, &count); if (!NT_SUCCESS(Status)) { goto out; } Status = SamQueryInformationGroup(GroupHandle, GroupNameInformation, (PVOID *)&NameInfo); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't query info group: 0x%x\n", Status)); goto out; } } else { Status = SamOpenAlias(DomainHandle, GENERIC_READ | GENERIC_EXECUTE, GroupId, &GroupHandle); if (!NT_SUCCESS(Status)) { goto out; } Status = SamGetMembersInAlias(GroupHandle, &ppsGroupMem, &count); if (!NT_SUCCESS(Status)) { goto out; } Status = SamQueryInformationAlias(GroupHandle, AliasNameInformation, (PVOID *)&NameInfo); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: Can't query info alias: 0x%x\n", Status)); goto out; } } // // The strings start after the member name pointer array. We leave // an extra member name pointer for the null-terminator. // pch = (PCHAR)(ppchMem + 1 + count); SpaceLeft = (ULONG)(PSX_CLIENT_PORT_MEMORY_SIZE - (ULONG_PTR)(pch - (ULONG_PTR)DataDest)); grp->gr_name = pch - (ULONG_PTR)DataDest; A.Buffer = pch; A.MaximumLength = (USHORT)SpaceLeft; Status = RtlUnicodeStringToAnsiString(&A, &NameInfo->Name, FALSE); if (!NT_SUCCESS(Status)) { goto out; } SpaceLeft -= A.Length; pch = pch + A.Length + 1; for (i = 0; i < count; ++i) { SAM_HANDLE UserHandle; PUSER_ACCOUNT_NAME_INFORMATION pUserInfo; ppchMem[i] = pch - (ULONG_PTR)DataDest; A.Buffer = pch; A.MaximumLength = (USHORT)SpaceLeft; if (Type == SidTypeGroup) { Status = SamOpenUser(DomainHandle, GENERIC_READ | GENERIC_EXECUTE, puGroupMem[i], &UserHandle); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: SamOpenUser: 0x%x\n", Status)); continue; } Status = SamQueryInformationUser(UserHandle, UserAccountNameInformation, (PVOID *)&pUserInfo); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: SamQueryInfoUser: 0x%x\n", Status)); } ASSERT(NT_SUCCESS(Status)); Status = SamCloseHandle(UserHandle); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: SamCloseHandle: 0x%x\n", Status)); } ASSERT(NT_SUCCESS(Status)); RtlUnicodeStringToAnsiString(&A, &pUserInfo->UserName, FALSE); SamFreeMemory(pUserInfo); } else { Status = GetUserNameFromSid(ppsGroupMem[i], &A); if (!NT_SUCCESS(Status)) { continue; } } SpaceLeft -= A.Length; pch = pch + A.Length + 1; } ppchMem[i] = NULL; *pLength = (int)((ULONG_PTR)(pch - (ULONG_PTR)DataDest)); SamCloseHandle(GroupHandle); return STATUS_SUCCESS; out: if (NULL != GroupHandle) { SamCloseHandle(GroupHandle); } if (NULL != puGroupMem) { SamFreeMemory(puGroupMem); } if (NULL != ppsGroupMem) { SamFreeMemory(ppsGroupMem); } if (NULL != puAttr) { SamFreeMemory(puAttr); } if (NULL != NameInfo) { SamFreeMemory(NameInfo); } return STATUS_BUFFER_TOO_SMALL; } // // MakeSid -- Attach the given relative id to the given Domain Sid to // make a new Sid, and return it. That new sid must be freed with // RtlFreeHeap. // PSID MakeSid( PSID DomainSid, ULONG RelativeId ) { PSID NewSid; NTSTATUS Status; UCHAR AuthCount; int i; AuthCount = *RtlSubAuthorityCountSid(DomainSid) + 1; NewSid = RtlAllocateHeap(PsxHeap, 0, RtlLengthRequiredSid(AuthCount)); if (NULL == NewSid) { return NULL; } Status = RtlInitializeSid(NewSid, RtlIdentifierAuthoritySid(DomainSid), AuthCount); if (!NT_SUCCESS(Status)) { KdPrint(("PSXSS: 0x%x\n", Status)); } ASSERT(NT_SUCCESS(Status)); // // Copy the Domain Sid. // for (i = 0; i < AuthCount - 1; ++i) { *RtlSubAuthoritySid(NewSid, i) = *RtlSubAuthoritySid(DomainSid, i); } // // Append the Relative Id. // *RtlSubAuthoritySid(NewSid, AuthCount - 1) = RelativeId; return NewSid; } // // ConvertPathToPsx -- Converts an ANSI_STRING representation of // a path to a posix format path. The ANSI_STRING's buffer is assumed // to point to a section of the ClientView memory, and the MaximumLength // member of the ANSI_STRING is assumed to be set to the maximum length // of the final path string. This function will modify the Buffer and // Length members of the input ANSI_STRING. This function will return // false if a working buffer cannot be allocated in the PsxHeap heap. // static BOOLEAN ConvertPathToPsx ( ANSI_STRING *A ) { PCHAR TmpBuff; PCHAR InRover; PCHAR OutRover; TmpBuff = RtlAllocateHeap(PsxHeap, 0, A->Length*2); if (NULL == TmpBuff) { return(FALSE); } if (*(A->Buffer) == '\0') { strcpy(TmpBuff, "//C/" ); } else { for (InRover = A->Buffer, OutRover = TmpBuff; *InRover != '\0'; ++InRover) { if (';' == *InRover) { // semis become colons *OutRover++ = ':'; } else if ('\\' == *InRover) { // back-slashes become forward-slashes *OutRover++ = '/'; } else if (':' == *(InRover + 1)) { // "X:" becomes "//X" - drive letter must be uppercase *OutRover++ = '/'; *OutRover++ = '/'; *OutRover++ = (CHAR)toupper(*InRover); ++InRover; // skip the colon } else { *OutRover++ = *InRover; } } *OutRover = '\0'; } strcpy(A->Buffer, TmpBuff); A->Length = (USHORT)strlen(A->Buffer); RtlFreeHeap(PsxHeap, 0, (PVOID)TmpBuff); return (TRUE); } PSID GetSpecialSid( uid_t Uid ) { PSID Sid; NTSTATUS Status; SID_IDENTIFIER_AUTHORITY Auth = SECURITY_NULL_SID_AUTHORITY; UCHAR uc; ULONG ul; Sid = RtlAllocateHeap(PsxHeap, 0, RtlLengthRequiredSid(1)); if (NULL == Sid) return NULL; Status = RtlInitializeSid(Sid, &Auth, 1); ASSERT(NT_SUCCESS(Status)); uc = (UCHAR)((Uid & 0xFFF) >> 8); RtlIdentifierAuthoritySid(Sid)->Value[5] = uc; ul = Uid & 0xF; *RtlSubAuthoritySid(Sid, 0) = ul; return Sid; }