You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
581 lines
14 KiB
581 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
adtutil.c
|
|
|
|
Abstract:
|
|
|
|
Misc helper functions
|
|
|
|
Author:
|
|
|
|
15-August-2000 kumarp
|
|
|
|
--*/
|
|
|
|
|
|
#include <lsapch2.h>
|
|
#include "adtp.h"
|
|
|
|
|
|
NTSTATUS
|
|
ImpersonateAnyClient(); // from ntdsa
|
|
|
|
VOID
|
|
UnImpersonateAnyClient(); // from ntdsa
|
|
|
|
|
|
|
|
ULONG
|
|
LsapSafeWcslen(
|
|
UNALIGNED WCHAR *p,
|
|
LONG MaxLength
|
|
)
|
|
/*++
|
|
|
|
Safewcslen - Strlen that won't exceed MaxLength
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to determine the size of a UNICODE_STRING
|
|
(taken from elfapi.c)
|
|
|
|
Arguments:
|
|
p - The string to count.
|
|
MaxLength - The maximum length to look at.
|
|
|
|
|
|
Return Value:
|
|
|
|
Number of bytes in the string (or MaxLength)
|
|
|
|
--*/
|
|
{
|
|
ULONG Count = 0;
|
|
|
|
if (p)
|
|
{
|
|
while ((MaxLength > 0) && (*p++ != UNICODE_NULL))
|
|
{
|
|
MaxLength -= sizeof(WCHAR);
|
|
Count += sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LsapIsValidUnicodeString(
|
|
IN PUNICODE_STRING pUString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify the unicode string. The string is invalid if:
|
|
The UNICODE_STRING structure ptr is NULL.
|
|
The MaximumLength field is invalid (too small).
|
|
The Length field is incorrect.
|
|
(taken from elfapi.c)
|
|
|
|
Arguments:
|
|
|
|
pUString - String to verify.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the string is valid
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
return !(!pUString ||
|
|
(pUString->MaximumLength < pUString->Length) ||
|
|
(pUString->Length != LsapSafeWcslen(pUString->Buffer,
|
|
pUString->Length)));
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsapAdtLookupDriveLetter(
|
|
IN PUNICODE_STRING FileName,
|
|
OUT PUSHORT DeviceNameLength,
|
|
OUT PWCHAR DriveLetter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will take a file name and compare it to the
|
|
list of device names obtained during LSA initialization.
|
|
If one of the device names matches the prefix of the file
|
|
name the corresponding drive letter will be returned.
|
|
|
|
Arguments:
|
|
|
|
FileName - Supplies a unicode string containing the file
|
|
name obtained from the file system.
|
|
|
|
DeviceNameLength - If successful, returns the length of
|
|
the device name.
|
|
|
|
DriveLetter - If successful, returns the drive letter
|
|
corresponding to the device object.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE of a mapping is found, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG i = 0;
|
|
PUNICODE_STRING DeviceName;
|
|
USHORT OldLength;
|
|
|
|
|
|
for (i = MAX_DRIVE_MAPPING - 1; i >= 0; i--)
|
|
{
|
|
|
|
if (DriveMappingArray[i].DeviceName.Buffer != NULL ) {
|
|
|
|
DeviceName = &DriveMappingArray[i].DeviceName;
|
|
|
|
//
|
|
// If the device name is longer than the passed file name,
|
|
// it can't be a match.
|
|
//
|
|
|
|
if ( DeviceName->Length > FileName->Length ) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Temporarily truncate the file name to be the same
|
|
// length as the device name by adjusting the length field
|
|
// in its unicode string structure. Then compare them and
|
|
// see if they match.
|
|
//
|
|
// The test above ensures that this is a safe thing to
|
|
// do.
|
|
//
|
|
|
|
OldLength = FileName->Length;
|
|
FileName->Length = DeviceName->Length;
|
|
|
|
|
|
if ( RtlEqualUnicodeString( FileName, DeviceName, TRUE ) ) {
|
|
|
|
//
|
|
// We've got a match.
|
|
//
|
|
|
|
FileName->Length = OldLength;
|
|
*DriveLetter = DriveMappingArray[i].DriveLetter;
|
|
*DeviceNameLength = DeviceName->Length;
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
FileName->Length = OldLength;
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapAdtSubstituteDriveLetter(
|
|
IN OUT PUNICODE_STRING FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a filename and replaces the device name part with a
|
|
drive letter, if possible.
|
|
|
|
The string will be edited directly in place, which means that
|
|
the Length field will be adjusted, and the Buffer contents will
|
|
be moved so that the drive letter is at the beginning of the
|
|
buffer. No memory will be allocated or freed.
|
|
|
|
Arguments:
|
|
|
|
FileName - Supplies a pointer to a unicode string containing
|
|
a filename.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
WCHAR DriveLetter;
|
|
USHORT DeviceNameLength;
|
|
PWCHAR p;
|
|
PWCHAR FilePart;
|
|
USHORT FilePartLength;
|
|
|
|
if ( LsapAdtLookupDriveLetter( FileName, &DeviceNameLength, &DriveLetter )) {
|
|
|
|
p = FileName->Buffer;
|
|
FilePart = (PWCHAR)((PCHAR)(FileName->Buffer) + DeviceNameLength);
|
|
FilePartLength = FileName->Length - DeviceNameLength;
|
|
|
|
|
|
*p = DriveLetter;
|
|
*++p = L':';
|
|
|
|
//
|
|
// THIS IS AN OVERLAPPED COPY! DO NOT USE RTLCOPYMEMORY!
|
|
//
|
|
|
|
RtlMoveMemory( ++p, FilePart, FilePartLength );
|
|
|
|
FileName->Length = FilePartLength + 2 * sizeof( WCHAR );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapQueryClientInfo(
|
|
PTOKEN_USER *UserSid,
|
|
PLUID AuthenticationId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine impersonates our client, opens the thread token, and
|
|
extracts the User Sid. It puts the Sid in memory allocated via
|
|
LsapAllocateLsaHeap, which must be freed by the caller.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to heap memory containing a copy of the Sid, or
|
|
NULL.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE TokenHandle;
|
|
ULONG ReturnLength;
|
|
TOKEN_STATISTICS TokenStats;
|
|
BOOLEAN bImpersonatingAnonymous = FALSE;
|
|
|
|
Status = NtOpenThreadToken(
|
|
NtCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE, // OpenAsSelf
|
|
&TokenHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Status != STATUS_NO_TOKEN)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
if (LsaDsStateInfo.DsInitializedAndRunning)
|
|
{
|
|
Status = I_RpcMapWin32Status(ImpersonateAnyClient());
|
|
}
|
|
else
|
|
{
|
|
Status = I_RpcMapWin32Status(RpcImpersonateClient(NULL));
|
|
}
|
|
|
|
if (Status == RPC_NT_CANNOT_SUPPORT)
|
|
{
|
|
Status = NtImpersonateAnonymousToken(NtCurrentThread());
|
|
|
|
bImpersonatingAnonymous = TRUE;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
NTSTATUS DbgStatus;
|
|
|
|
Status = NtOpenThreadToken(
|
|
NtCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE, // OpenAsSelf
|
|
&TokenHandle
|
|
);
|
|
|
|
if (bImpersonatingAnonymous)
|
|
{
|
|
HANDLE NewTokenHandle = NULL;
|
|
|
|
DbgStatus = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
(PVOID)&NewTokenHandle,
|
|
(ULONG)sizeof(HANDLE)
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(DbgStatus));
|
|
}
|
|
else
|
|
{
|
|
if (LsaDsStateInfo.DsInitializedAndRunning)
|
|
{
|
|
UnImpersonateAnyClient();
|
|
}
|
|
else
|
|
{
|
|
DbgStatus = I_RpcMapWin32Status(RpcRevertToSelf());
|
|
|
|
ASSERT(NT_SUCCESS(DbgStatus));
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
else if (Status == RPC_NT_NO_CALL_ACTIVE)
|
|
{
|
|
Status = NtOpenProcessToken(
|
|
NtCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&TokenHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = NtQueryInformationToken(
|
|
TokenHandle,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&ReturnLength
|
|
);
|
|
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
NtClose(TokenHandle);
|
|
return Status;
|
|
}
|
|
|
|
*UserSid = LsapAllocateLsaHeap(ReturnLength);
|
|
|
|
if (*UserSid == NULL)
|
|
{
|
|
NtClose(TokenHandle);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(
|
|
TokenHandle,
|
|
TokenUser,
|
|
*UserSid,
|
|
ReturnLength,
|
|
&ReturnLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
NtClose(TokenHandle);
|
|
LsapFreeLsaHeap(*UserSid);
|
|
*UserSid = NULL;
|
|
return Status;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(
|
|
TokenHandle,
|
|
TokenStatistics,
|
|
(PVOID)&TokenStats,
|
|
sizeof(TOKEN_STATISTICS),
|
|
&ReturnLength
|
|
);
|
|
|
|
NtClose(TokenHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
LsapFreeLsaHeap(*UserSid);
|
|
*UserSid = NULL;
|
|
return Status;
|
|
}
|
|
|
|
*AuthenticationId = TokenStats.AuthenticationId;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
LsapIsLocalOrNetworkService(
|
|
IN PUNICODE_STRING pUserName,
|
|
IN PUNICODE_STRING pUserDomain
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if the passed account name represents
|
|
a local or network service
|
|
|
|
Arguments:
|
|
|
|
pUserName - unicode user name
|
|
|
|
pUserDomain - unicode domain name
|
|
|
|
Return Value:
|
|
|
|
TRUE if the passed account name represents a local or network service
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
#define LOCALSERVICE_NAME L"LocalService"
|
|
#define NETWORKSERVICE_NAME L"NetworkService"
|
|
#define NTAUTHORITY_NAME L"NT AUTHORITY"
|
|
|
|
static UNICODE_STRING LocalServiceName = { sizeof(LOCALSERVICE_NAME) - sizeof(WCHAR),
|
|
sizeof(LOCALSERVICE_NAME),
|
|
LOCALSERVICE_NAME };
|
|
|
|
static UNICODE_STRING NetworkServiceName = { sizeof(NETWORKSERVICE_NAME) - sizeof(WCHAR),
|
|
sizeof(NETWORKSERVICE_NAME),
|
|
NETWORKSERVICE_NAME };
|
|
|
|
static UNICODE_STRING NTAuthorityName = { sizeof(NTAUTHORITY_NAME) - sizeof(WCHAR),
|
|
sizeof(NTAUTHORITY_NAME),
|
|
NTAUTHORITY_NAME };
|
|
|
|
PUNICODE_STRING pLocalServiceName;
|
|
PUNICODE_STRING pNetworkServiceName;
|
|
PUNICODE_STRING pLocalDomainName;
|
|
|
|
if ( !pUserName || !pUserDomain )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Hardcoded english strings for LocalService and NetworkService
|
|
// since the account names may come from the registry (which isn't
|
|
// localized).
|
|
//
|
|
|
|
pLocalDomainName = &WellKnownSids[LsapLocalServiceSidIndex].DomainName;
|
|
pNetworkServiceName = &WellKnownSids[LsapNetworkServiceSidIndex].Name;
|
|
pLocalServiceName = &WellKnownSids[LsapLocalServiceSidIndex].Name;
|
|
|
|
//
|
|
// check both hardcode and localized names
|
|
//
|
|
|
|
if (((RtlCompareUnicodeString(&NTAuthorityName, pUserDomain, TRUE) == 0) &&
|
|
((RtlCompareUnicodeString(&LocalServiceName, pUserName, TRUE) == 0) ||
|
|
(RtlCompareUnicodeString(&NetworkServiceName, pUserName, TRUE) == 0))) ||
|
|
|
|
((RtlCompareUnicodeString(pLocalDomainName, pUserDomain, TRUE) == 0) &&
|
|
((RtlCompareUnicodeString(pLocalServiceName, pUserName, TRUE) == 0) ||
|
|
(RtlCompareUnicodeString(pNetworkServiceName, pUserName, TRUE) == 0))))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
LsapIsAnonymous(
|
|
IN PUNICODE_STRING pUserName,
|
|
IN PUNICODE_STRING pUserDomain
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if the passed account name represents
|
|
an anonymous logon.
|
|
|
|
Arguments:
|
|
|
|
pUserName - unicode user name
|
|
|
|
pUserDomain - unicode domain name
|
|
|
|
Return Value:
|
|
|
|
TRUE if the passed account name represents the anonymous logon.
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
#define ANONYMOUS_NAME L"ANONYMOUS LOGON"
|
|
#define NTAUTHORITY_NAME L"NT AUTHORITY"
|
|
|
|
static UNICODE_STRING AnonymousName = { sizeof(ANONYMOUS_NAME) - sizeof(WCHAR),
|
|
sizeof(ANONYMOUS_NAME),
|
|
ANONYMOUS_NAME };
|
|
|
|
static UNICODE_STRING NTAuthorityName = { sizeof(NTAUTHORITY_NAME) - sizeof(WCHAR),
|
|
sizeof(NTAUTHORITY_NAME),
|
|
NTAUTHORITY_NAME };
|
|
|
|
PUNICODE_STRING pLocalDomainName = &WellKnownSids[LsapLocalServiceSidIndex].DomainName;
|
|
PUNICODE_STRING pAnonymousName = &WellKnownSids[LsapAnonymousSidIndex].Name;
|
|
|
|
if ( !pUserName || !pUserDomain )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// check both hardcode and localized names
|
|
//
|
|
|
|
if (((RtlCompareUnicodeString(&NTAuthorityName, pUserDomain, TRUE) == 0) &&
|
|
(RtlCompareUnicodeString(&AnonymousName, pUserName, TRUE) == 0)) ||
|
|
|
|
((RtlCompareUnicodeString(pLocalDomainName, pUserDomain, TRUE) == 0) &&
|
|
(RtlCompareUnicodeString(pAnonymousName, pUserName, TRUE) == 0)))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|