497 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | ||
| 
 | ||
| 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;
 | ||
| 
 | ||
|     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 (NT_SUCCESS(Status))
 | ||
|         {
 | ||
|             Status = NtOpenThreadToken(
 | ||
|                          NtCurrentThread(),
 | ||
|                          TOKEN_QUERY,
 | ||
|                          TRUE,                    // OpenAsSelf
 | ||
|                          &TokenHandle
 | ||
|                          );
 | ||
| 
 | ||
|             if ( LsaDsStateInfo.DsInitializedAndRunning )
 | ||
|             {
 | ||
|                 UnImpersonateAnyClient();
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 NTSTATUS DbgStatus;
 | ||
| 
 | ||
|                 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 ) {
 | ||
| 
 | ||
|         (void) 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:
 | ||
| 
 | ||
|     None.
 | ||
| 
 | ||
| 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) - 2,
 | ||
|                                                 sizeof(LOCALSERVICE_NAME),
 | ||
|                                                 LOCALSERVICE_NAME };
 | ||
| 
 | ||
|     static UNICODE_STRING  NetworkServiceName = { sizeof(NETWORKSERVICE_NAME) - 2,
 | ||
|                                                   sizeof(NETWORKSERVICE_NAME),
 | ||
|                                                   NETWORKSERVICE_NAME };
 | ||
| 
 | ||
|     static UNICODE_STRING  NTAuthorityName = { sizeof(NTAUTHORITY_NAME) - 2,
 | ||
|                                                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;
 | ||
|     }
 | ||
|         
 | ||
| }
 |