go my file uploader
This commit is contained in:
480
phlib/lsasup.c
Normal file
480
phlib/lsasup.c
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* Process Hacker -
|
||||
* LSA support functions
|
||||
*
|
||||
* Copyright (C) 2010-2011 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are functions which communicate with LSA or are support functions. They replace certain
|
||||
* Win32 security-related functions such as LookupAccountName, LookupAccountSid and
|
||||
* LookupPrivilege*, which are badly designed. (LSA already allocates the return values for the
|
||||
* caller, yet the Win32 functions insist on their callers providing their own buffers.)
|
||||
*/
|
||||
|
||||
#include <ph.h>
|
||||
#include <lsasup.h>
|
||||
|
||||
static LSA_HANDLE PhLookupPolicyHandle = NULL;
|
||||
|
||||
NTSTATUS PhOpenLsaPolicy(
|
||||
_Out_ PLSA_HANDLE PolicyHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_opt_ PUNICODE_STRING SystemName
|
||||
)
|
||||
{
|
||||
OBJECT_ATTRIBUTES oa = { 0 };
|
||||
|
||||
return LsaOpenPolicy(
|
||||
SystemName,
|
||||
&oa,
|
||||
DesiredAccess,
|
||||
PolicyHandle
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a handle to the local LSA policy with POLICY_LOOKUP_NAMES access.
|
||||
*
|
||||
* \remarks Do not close the handle; it is cached.
|
||||
*/
|
||||
LSA_HANDLE PhGetLookupPolicyHandle(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
LSA_HANDLE lookupPolicyHandle;
|
||||
LSA_HANDLE newLookupPolicyHandle;
|
||||
|
||||
lookupPolicyHandle = PhLookupPolicyHandle;
|
||||
|
||||
// If there is no cached handle, open one.
|
||||
|
||||
if (!lookupPolicyHandle)
|
||||
{
|
||||
if (NT_SUCCESS(PhOpenLsaPolicy(
|
||||
&newLookupPolicyHandle,
|
||||
POLICY_LOOKUP_NAMES,
|
||||
NULL
|
||||
)))
|
||||
{
|
||||
// We succeeded in opening a policy handle, and since we did not have a cached handle
|
||||
// before, we will now store it.
|
||||
|
||||
lookupPolicyHandle = _InterlockedCompareExchangePointer(
|
||||
&PhLookupPolicyHandle,
|
||||
newLookupPolicyHandle,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!lookupPolicyHandle)
|
||||
{
|
||||
// Success. Use our handle.
|
||||
lookupPolicyHandle = newLookupPolicyHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Someone already placed a handle in the cache. Close our handle and use their
|
||||
// handle.
|
||||
LsaClose(newLookupPolicyHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lookupPolicyHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a privilege from its LUID.
|
||||
*
|
||||
* \param PrivilegeValue The LUID of a privilege.
|
||||
* \param PrivilegeName A variable which receives a pointer to a string containing the privilege
|
||||
* name. You must free the string using PhDereferenceObject() when you no longer need it.
|
||||
*/
|
||||
BOOLEAN PhLookupPrivilegeName(
|
||||
_In_ PLUID PrivilegeValue,
|
||||
_Out_ PPH_STRING *PrivilegeName
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PUNICODE_STRING name;
|
||||
|
||||
status = LsaLookupPrivilegeName(
|
||||
PhGetLookupPolicyHandle(),
|
||||
PrivilegeValue,
|
||||
&name
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return FALSE;
|
||||
|
||||
*PrivilegeName = PhCreateStringFromUnicodeString(name);
|
||||
LsaFreeMemory(name);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display name of a privilege from its name.
|
||||
*
|
||||
* \param PrivilegeName The name of a privilege.
|
||||
* \param PrivilegeDisplayName A variable which receives a pointer to a string containing the
|
||||
* privilege's display name. You must free the string using PhDereferenceObject() when you no longer
|
||||
* need it.
|
||||
*/
|
||||
BOOLEAN PhLookupPrivilegeDisplayName(
|
||||
_In_ PPH_STRINGREF PrivilegeName,
|
||||
_Out_ PPH_STRING *PrivilegeDisplayName
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING privilegeName;
|
||||
PUNICODE_STRING displayName;
|
||||
SHORT language;
|
||||
|
||||
if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))
|
||||
return FALSE;
|
||||
|
||||
status = LsaLookupPrivilegeDisplayName(
|
||||
PhGetLookupPolicyHandle(),
|
||||
&privilegeName,
|
||||
&displayName,
|
||||
&language
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return FALSE;
|
||||
|
||||
*PrivilegeDisplayName = PhCreateStringFromUnicodeString(displayName);
|
||||
LsaFreeMemory(displayName);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the LUID of a privilege from its name.
|
||||
*
|
||||
* \param PrivilegeName The name of a privilege.
|
||||
* \param PrivilegeValue A variable which receives the LUID of the privilege.
|
||||
*/
|
||||
BOOLEAN PhLookupPrivilegeValue(
|
||||
_In_ PPH_STRINGREF PrivilegeName,
|
||||
_Out_ PLUID PrivilegeValue
|
||||
)
|
||||
{
|
||||
UNICODE_STRING privilegeName;
|
||||
|
||||
if (!PhStringRefToUnicodeString(PrivilegeName, &privilegeName))
|
||||
return FALSE;
|
||||
|
||||
return NT_SUCCESS(LsaLookupPrivilegeValue(
|
||||
PhGetLookupPolicyHandle(),
|
||||
&privilegeName,
|
||||
PrivilegeValue
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about a SID.
|
||||
*
|
||||
* \param Sid A SID to query.
|
||||
* \param Name A variable which receives a pointer to a string containing the SID's name. You must
|
||||
* free the string using PhDereferenceObject() when you no longer need it.
|
||||
* \param DomainName A variable which receives a pointer to a string containing the SID's domain
|
||||
* name. You must free the string using PhDereferenceObject() when you no longer need it.
|
||||
* \param NameUse A variable which receives the SID's usage.
|
||||
*/
|
||||
NTSTATUS PhLookupSid(
|
||||
_In_ PSID Sid,
|
||||
_Out_opt_ PPH_STRING *Name,
|
||||
_Out_opt_ PPH_STRING *DomainName,
|
||||
_Out_opt_ PSID_NAME_USE NameUse
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
LSA_HANDLE policyHandle;
|
||||
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
|
||||
PLSA_TRANSLATED_NAME names;
|
||||
|
||||
policyHandle = PhGetLookupPolicyHandle();
|
||||
|
||||
referencedDomains = NULL;
|
||||
names = NULL;
|
||||
|
||||
if (NT_SUCCESS(status = LsaLookupSids(
|
||||
policyHandle,
|
||||
1,
|
||||
&Sid,
|
||||
&referencedDomains,
|
||||
&names
|
||||
)))
|
||||
{
|
||||
if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
|
||||
{
|
||||
if (Name)
|
||||
{
|
||||
*Name = PhCreateStringFromUnicodeString(&names[0].Name);
|
||||
}
|
||||
|
||||
if (DomainName)
|
||||
{
|
||||
if (names[0].DomainIndex >= 0)
|
||||
{
|
||||
PLSA_TRUST_INFORMATION trustInfo;
|
||||
|
||||
trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
|
||||
*DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
*DomainName = PhReferenceEmptyString();
|
||||
}
|
||||
}
|
||||
|
||||
if (NameUse)
|
||||
{
|
||||
*NameUse = names[0].Use;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_NONE_MAPPED;
|
||||
}
|
||||
}
|
||||
|
||||
// LsaLookupSids allocates memory even if it returns STATUS_NONE_MAPPED.
|
||||
if (referencedDomains)
|
||||
LsaFreeMemory(referencedDomains);
|
||||
if (names)
|
||||
LsaFreeMemory(names);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about a name.
|
||||
*
|
||||
* \param Name A name to query.
|
||||
* \param Sid A variable which receives a pointer to a SID. You must free the SID using PhFree()
|
||||
* when you no longer need it.
|
||||
* \param DomainName A variable which receives a pointer to a string containing the SID's domain
|
||||
* name. You must free the string using PhDereferenceObject() when you no longer need it.
|
||||
* \param NameUse A variable which receives the SID's usage.
|
||||
*/
|
||||
NTSTATUS PhLookupName(
|
||||
_In_ PPH_STRINGREF Name,
|
||||
_Out_opt_ PSID *Sid,
|
||||
_Out_opt_ PPH_STRING *DomainName,
|
||||
_Out_opt_ PSID_NAME_USE NameUse
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
LSA_HANDLE policyHandle;
|
||||
UNICODE_STRING name;
|
||||
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
|
||||
PLSA_TRANSLATED_SID2 sids;
|
||||
|
||||
if (!PhStringRefToUnicodeString(Name, &name))
|
||||
return STATUS_NAME_TOO_LONG;
|
||||
|
||||
policyHandle = PhGetLookupPolicyHandle();
|
||||
referencedDomains = NULL;
|
||||
sids = NULL;
|
||||
|
||||
if (NT_SUCCESS(status = LsaLookupNames2(
|
||||
policyHandle,
|
||||
0,
|
||||
1,
|
||||
&name,
|
||||
&referencedDomains,
|
||||
&sids
|
||||
)))
|
||||
{
|
||||
if (sids[0].Use != SidTypeInvalid && sids[0].Use != SidTypeUnknown)
|
||||
{
|
||||
if (Sid)
|
||||
{
|
||||
PSID sid;
|
||||
ULONG sidLength;
|
||||
|
||||
sidLength = RtlLengthSid(sids[0].Sid);
|
||||
sid = PhAllocate(sidLength);
|
||||
memcpy(sid, sids[0].Sid, sidLength);
|
||||
|
||||
*Sid = sid;
|
||||
}
|
||||
|
||||
if (DomainName)
|
||||
{
|
||||
if (sids[0].DomainIndex >= 0)
|
||||
{
|
||||
PLSA_TRUST_INFORMATION trustInfo;
|
||||
|
||||
trustInfo = &referencedDomains->Domains[sids[0].DomainIndex];
|
||||
*DomainName = PhCreateStringFromUnicodeString(&trustInfo->Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
*DomainName = PhReferenceEmptyString();
|
||||
}
|
||||
}
|
||||
|
||||
if (NameUse)
|
||||
{
|
||||
*NameUse = sids[0].Use;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_NONE_MAPPED;
|
||||
}
|
||||
}
|
||||
|
||||
// LsaLookupNames2 allocates memory even if it returns STATUS_NONE_MAPPED.
|
||||
if (referencedDomains)
|
||||
LsaFreeMemory(referencedDomains);
|
||||
if (sids)
|
||||
LsaFreeMemory(sids);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a SID.
|
||||
*
|
||||
* \param Sid A SID to query.
|
||||
* \param IncludeDomain TRUE to include the domain name, otherwise FALSE.
|
||||
* \param NameUse A variable which receives the SID's usage.
|
||||
*
|
||||
* \return A pointer to a string containing the name of the SID in the following format:
|
||||
* domain\\name. You must free the string using PhDereferenceObject() when you no longer need it. If
|
||||
* an error occurs, the function returns NULL.
|
||||
*/
|
||||
PPH_STRING PhGetSidFullName(
|
||||
_In_ PSID Sid,
|
||||
_In_ BOOLEAN IncludeDomain,
|
||||
_Out_opt_ PSID_NAME_USE NameUse
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PPH_STRING fullName;
|
||||
LSA_HANDLE policyHandle;
|
||||
PLSA_REFERENCED_DOMAIN_LIST referencedDomains;
|
||||
PLSA_TRANSLATED_NAME names;
|
||||
|
||||
policyHandle = PhGetLookupPolicyHandle();
|
||||
|
||||
referencedDomains = NULL;
|
||||
names = NULL;
|
||||
|
||||
if (NT_SUCCESS(status = LsaLookupSids(
|
||||
policyHandle,
|
||||
1,
|
||||
&Sid,
|
||||
&referencedDomains,
|
||||
&names
|
||||
)))
|
||||
{
|
||||
if (names[0].Use != SidTypeInvalid && names[0].Use != SidTypeUnknown)
|
||||
{
|
||||
PWSTR domainNameBuffer;
|
||||
ULONG domainNameLength;
|
||||
|
||||
if (IncludeDomain && names[0].DomainIndex >= 0)
|
||||
{
|
||||
PLSA_TRUST_INFORMATION trustInfo;
|
||||
|
||||
trustInfo = &referencedDomains->Domains[names[0].DomainIndex];
|
||||
domainNameBuffer = trustInfo->Name.Buffer;
|
||||
domainNameLength = trustInfo->Name.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
domainNameBuffer = NULL;
|
||||
domainNameLength = 0;
|
||||
}
|
||||
|
||||
if (domainNameBuffer && domainNameLength != 0)
|
||||
{
|
||||
fullName = PhCreateStringEx(NULL, domainNameLength + sizeof(WCHAR) + names[0].Name.Length);
|
||||
memcpy(&fullName->Buffer[0], domainNameBuffer, domainNameLength);
|
||||
fullName->Buffer[domainNameLength / sizeof(WCHAR)] = '\\';
|
||||
memcpy(&fullName->Buffer[domainNameLength / sizeof(WCHAR) + 1], names[0].Name.Buffer, names[0].Name.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
fullName = PhCreateStringFromUnicodeString(&names[0].Name);
|
||||
}
|
||||
|
||||
if (NameUse)
|
||||
{
|
||||
*NameUse = names[0].Use;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fullName = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fullName = NULL;
|
||||
}
|
||||
|
||||
if (referencedDomains)
|
||||
LsaFreeMemory(referencedDomains);
|
||||
if (names)
|
||||
LsaFreeMemory(names);
|
||||
|
||||
return fullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a SDDL string representation of a SID.
|
||||
*
|
||||
* \param Sid A SID to query.
|
||||
*
|
||||
* \return A pointer to a string containing the SDDL representation of the SID. You must free the
|
||||
* string using PhDereferenceObject() when you no longer need it. If an error occurs, the function
|
||||
* returns NULL.
|
||||
*/
|
||||
PPH_STRING PhSidToStringSid(
|
||||
_In_ PSID Sid
|
||||
)
|
||||
{
|
||||
PPH_STRING string;
|
||||
UNICODE_STRING us;
|
||||
|
||||
string = PhCreateStringEx(NULL, MAX_UNICODE_STACK_BUFFER_LENGTH * sizeof(WCHAR));
|
||||
PhStringRefToUnicodeString(&string->sr, &us);
|
||||
|
||||
if (NT_SUCCESS(RtlConvertSidToUnicodeString(
|
||||
&us,
|
||||
Sid,
|
||||
FALSE
|
||||
)))
|
||||
{
|
||||
string->Length = us.Length;
|
||||
string->Buffer[us.Length / sizeof(WCHAR)] = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user