windows-nt/Source/XPSP1/NT/base/subsys/posix/psxss/sysdb.c

1257 lines
27 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*--
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 <pwd.h>
#include <grp.h>
#include <ntsam.h>
#include <ntlsa.h>
#include <seposix.h>
#include <ctype.h>
#define UNICODE
#include <windef.h>
#include <winbase.h>
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;
}