#include <windows.h>
#include <ntsecapi.h>
#include <stdio.h>
#pragma hdrstop



/*******************************************************************
This sample enumerates a machine's trusted domains. There are
two other samples for LSA stuff in the Win32/Platform SDK, under
\mssdk\samples\win32\winnt\security\lsapriv\ and ...\lsasamp\. The
latter directory also contains the help file describing the LSA
functions. There are also a few KB articles -- query for the term
"LsaOpenPolicy" to get them.
********************************************************************/



#define	gle	GetLastError()


#define STATUS_NO_MORE_ENTRIES 0x8000001aL // from NTSTATUS.H (in DDK)



int main( int argc, char *argv[] );
void err( const char *msg, NTSTATUS nts, bool isNtStatus = true );



class LsaUnicodeString: public _LSA_UNICODE_STRING
{
public:
	LsaUnicodeString( int maxSize = 512 );
	~LsaUnicodeString();
	void init( int maxSize = 512 );
	operator LSA_UNICODE_STRING *();
	operator char *();
	const LsaUnicodeString& operator=( const char *s );
};



LsaUnicodeString::LsaUnicodeString( int maxSize /* = 512 */ )
{
	Buffer = NULL;
	init( maxSize );
}



void LsaUnicodeString::init( int maxSize /* = 512 */ )
{
	if ( Buffer )
		free( Buffer );
	Length = 0;
	MaximumLength = maxSize;
	Buffer = ( maxSize == 0 )? NULL: (wchar_t *) malloc( maxSize );
	if ( Buffer )
		*Buffer = L'\0';
}



LsaUnicodeString::operator LSA_UNICODE_STRING *()
{
	return static_cast<LSA_UNICODE_STRING *>( this );
}



LsaUnicodeString::operator char *()
{
	char *ansiBuf;

	ansiBuf = (char *) malloc( Length / 2 + 1 );
	int n = WideCharToMultiByte( CP_ACP, 0, Buffer, Length / 2, ansiBuf, Length + 2 / 1, NULL, NULL );
	ansiBuf[n] = '\0';
	return ansiBuf;
}



LsaUnicodeString::~LsaUnicodeString()
{
	if ( Buffer )
		free( Buffer );
}



const LsaUnicodeString& LsaUnicodeString::operator=( const char *s )
{
	if ( strlen( s ) * 2 >= MaximumLength )
		init( strlen( s ) ); // get new buffer
	MultiByteToWideChar( CP_ACP, 0, s, -1, Buffer, MaximumLength * 2 );
	Length = strlen( s ) * 2;
	return *this;
}



void err( const char *msg, NTSTATUS nts, bool isNtStatus /* = true */ )
{
	DWORD e;

	if ( nts == 0 )
		return;

	if ( isNtStatus )
	{
		e = LsaNtStatusToWinError( nts );
		printf( "%s: ntstatus %lu [%lXh], gle %lu\n", msg, nts, nts, e );
	}
	else
	{
		printf( "%s: gle %lu\n", msg, nts );
	}

	exit( 1 );
}



void print_sid( PSID ps )
{
	PSID_IDENTIFIER_AUTHORITY psia;
	DWORD subAuthCount, i;

	psia = GetSidIdentifierAuthority( ps );
	subAuthCount = *GetSidSubAuthorityCount( ps );
	printf( "[S-%lu-", SID_REVISION );

	if ( ( psia->Value[0] != 0 ) || ( psia->Value[1] != 0 ) )
		printf( "0x%02hx%02hx%02hx%02hx%02hx%02hx", (USHORT) psia->Value[0], (USHORT) psia->Value[1],
			(USHORT) psia->Value[2], (USHORT) psia->Value[3], (USHORT) psia->Value[4], (USHORT) psia->Value[5] );
	else
		printf( "%lu", (ULONG) ( psia->Value[5] ) + (ULONG) ( psia->Value[4] << 8 ) +
		(ULONG) ( psia->Value[3] << 16 ) + (ULONG) ( psia->Value[2] << 24 ) );

	for ( i = 0; i < subAuthCount; ++ i )
		printf( "-%lu", *GetSidSubAuthority( ps, i ) );
	putchar( ']' );
}



int main( int argc, char *argv[] )
{
	if ( argc > 2 )
	{
		puts( "Usage: lsa_letd [<system name>]" );
		puts( "Enumerates trusted domains on the named machine." );
		puts( "<system name> is the machine where the lookup will execute." );
		return 1;
	}


	// open the policy object on the target computer

	static SECURITY_QUALITY_OF_SERVICE sqos = { sizeof SECURITY_QUALITY_OF_SERVICE, SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE };
	static LSA_OBJECT_ATTRIBUTES lsaOA = { sizeof LSA_OBJECT_ATTRIBUTES, NULL, NULL, 0, NULL, &sqos };
	NTSTATUS nts;
	LSA_HANDLE polHandle;
	LsaUnicodeString systemName;

	if ( argc >= 2 )
		systemName = argv[1];

	nts = LsaOpenPolicy( argc == 1? NULL: systemName, &lsaOA, POLICY_VIEW_LOCAL_INFORMATION |
		GENERIC_READ | GENERIC_EXECUTE | POLICY_ALL_ACCESS, &polHandle );
	err( "LOP()", nts );

	// -----------------------------------------------------------------------------------------------
	// first, we need the account domain (local accounts; for DCs, all accounts)

	POLICY_ACCOUNT_DOMAIN_INFO *ppadi = NULL;
	char *p;

	nts = LsaQueryInformationPolicy( polHandle, PolicyAccountDomainInformation, (void **) &ppadi );
	err( "LQIP( PADI )", nts );
	p = (char *) *( (LsaUnicodeString *) &ppadi->DomainName );
	printf( "Account domain: %s, SID: ", p );
	free( p );
	print_sid( ppadi->DomainSid );
	putchar( '\n' );
	if ( ppadi != NULL )
		LsaFreeMemory( ppadi );

	// -----------------------------------------------------------------------------------------------
	// next, get the primary domain (domain members -- self-evident; WG members -- name of WG, no SID;
	// DCs -- name of domain == same as account domain). Note -- filtering this info is YOUR job!

	POLICY_PRIMARY_DOMAIN_INFO *pppdi = NULL;

	nts = LsaQueryInformationPolicy( polHandle, PolicyPrimaryDomainInformation, (void **) &pppdi );
	err( "LQIP( PPDI )", nts );
	p = (char *) *( (LsaUnicodeString *) &pppdi->Name );
	printf( "Primary domain: %s, SID: ", p );
	free( p );
	print_sid( pppdi->Sid );
	putchar( '\n' );
	if ( pppdi != NULL )
		LsaFreeMemory( pppdi );

	// -----------------------------------------------------------------------------------------------
	// now, get other trusted domains

	LSA_ENUMERATION_HANDLE enumHandle = 0;
	LSA_TRUST_INFORMATION *plti;
	void *buf;
	DWORD count = 0, j;
	int i;

	for ( i = 0; ; ++ i )
	{
		buf = NULL;
		nts = LsaEnumerateTrustedDomains( polHandle, &enumHandle, &buf, 2048, &count );
		if ( nts == STATUS_NO_MORE_ENTRIES )
			break; // buf must be NULL here, so no mem leak

		err( "LETD()", nts );

		printf( "\nBatch %d: %lu items\n", i + 1, count );
		for ( plti = (LSA_TRUST_INFORMATION *) buf, j = 0; j < count; ++ j, ++ plti )
		{
			p = (char *) *( (LsaUnicodeString *) &plti->Name );
			printf( "[%lu] %s, SID: ", j, p );
			free( p );
			print_sid( plti->Sid );
			putchar( '\n' );
		}

		if ( buf != NULL )
			LsaFreeMemory( buf );
	}

	LsaClose( polHandle );

	return 0;
}

