windows-nt/Source/XPSP1/NT/ds/security/tools/dsacls/utils.cpp
2020-09-26 16:20:57 +08:00

895 lines
23 KiB
C++

/*++
Copyright (c) 1998 - 1998 Microsoft Corporation
Module Name: utils.cpp
Abstract: This Module implements the utility routines for dsacls
Author: hitesh raigandhi (hiteshr )
Environment:User Mode
Revision History:
--*/
#include "stdafx.h"
#include "utils.h"
#include "dsace.h"
#include "dsacls.h"
/*******************************************************************
NAME: GetAccountNameFromSid
SYNOPSIS: Convert Sid to Account Name
ENTRY: pszServerName: Server name at which to look for
pSid : Pointer to Sid
EXIT: ppszName : Gets pointer to Account Name
RETURNS: ERROR_SUCCESS if Successful
ERROR_NOT_ENOUGH_MEMORY
NOTES: If LookupAccountName resolve the sid, it is
converted in to string and returned
HISTORY:
hiteshr July-1999 Created
********************************************************************/
DWORD GetAccountNameFromSid( LPWSTR pszServerName,
PSID pSid,
LPWSTR * ppszName )
{
LPWSTR pszAccountName = NULL;
LPWSTR pszDomainName = NULL;
DWORD cbAccountName = 0 ;
DWORD cbDomainName = 0;
SID_NAME_USE Use ;
DWORD dwErr = ERROR_SUCCESS;
*ppszName = NULL;
if( LookupAccountSid( pszServerName, // name of local or remote computer
pSid, // security identifier
NULL, // account name buffer
&cbAccountName,
NULL ,
&cbDomainName ,
&Use ) == FALSE )
{
dwErr = GetLastError();
if( dwErr != ERROR_INSUFFICIENT_BUFFER )
{
//Convert Sid to String
if( !ConvertSidToStringSid( pSid, ppszName ) )
dwErr = GetLastError();
else
dwErr = ERROR_SUCCESS;
goto FAILURE_RETURN;
}
else
dwErr = ERROR_SUCCESS;
}
pszAccountName = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cbAccountName +1 ) * sizeof( WCHAR ) );
if( pszAccountName == NULL )
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto FAILURE_RETURN;
}
pszDomainName = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cbDomainName + 1 )* sizeof( WCHAR ) );
if( pszDomainName == NULL )
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto FAILURE_RETURN;
}
if( LookupAccountSid( pszServerName, // name of local or remote computer
pSid, // security identifier
pszAccountName, // account name buffer
&cbAccountName,
pszDomainName ,
&cbDomainName ,
&Use ) == FALSE )
{
dwErr = GetLastError();
goto FAILURE_RETURN;
}
*ppszName = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cbAccountName + cbDomainName + 2 ) * sizeof( WCHAR ) );
if( *ppszName == NULL )
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto FAILURE_RETURN;
}
*ppszName[0] = NULL;
if( cbDomainName )
{
wcscpy( *ppszName, pszDomainName );
wcscat( *ppszName, L"\\" );
}
wcscat( *ppszName, pszAccountName );
FAILURE_RETURN:
if( pszDomainName )
LocalFree( pszDomainName );
if( pszAccountName )
LocalFree( pszAccountName );
return dwErr;
}
/*******************************************************************
NAME: GetSidFromAccountName
SYNOPSIS: Converts AccountName into SID
********************************************************************/
DWORD GetSidFromAccountName( LPWSTR pszServerName,
PSID *ppSid,
LPWSTR pszName )
{
LPWSTR pszDomainName = NULL;
DWORD cbSid = 0 ;
DWORD cbDomainName = 0;
SID_NAME_USE Use ;
DWORD dwErr = ERROR_SUCCESS;
if( LookupAccountName(pszServerName, // name of local or remote computer
pszName, // security identifier
NULL, // account name buffer
&cbSid,
NULL ,
&cbDomainName ,
&Use ) == FALSE )
{
dwErr = GetLastError();
if( dwErr != ERROR_INSUFFICIENT_BUFFER )
goto FAILURE_RETURN;
else
dwErr = ERROR_SUCCESS;
}
*ppSid = (PSID)LocalAlloc( LMEM_FIXED, cbSid );
CHECK_NULL( *ppSid, FAILURE_RETURN );
pszDomainName = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cbDomainName + 1 )* sizeof( WCHAR ) );
CHECK_NULL( pszDomainName, FAILURE_RETURN );
if( LookupAccountName( pszServerName, // name of local or remote computer
pszName, // security identifier
*ppSid, // account name buffer
&cbSid,
pszDomainName ,
&cbDomainName ,
&Use ) == FALSE )
{
dwErr = GetLastError();
goto FAILURE_RETURN;
}
goto SUCCESS_RETURN;
FAILURE_RETURN:
if( pszDomainName )
LocalFree( pszDomainName );
if( *ppSid )
LocalFree( *ppSid );
SUCCESS_RETURN:
return dwErr;
}
/*******************************************************************
NAME: GetAceSid
SYNOPSIS: Gets pointer to SID from an ACE
ENTRY: pAce - pointer to ACE
EXIT:
RETURNS: Pointer to SID if successful, NULL otherwise
NOTES:
HISTORY:
JeffreyS 08-Oct-1996 Created
********************************************************************/
PSID
GetAceSid(PACE_HEADER pAce)
{
switch (pAce->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
return (PSID)&((PKNOWN_ACE)pAce)->SidStart;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
return RtlObjectAceSid(pAce);
}
return NULL;
}
/*******************************************************************
NAME: GetGlobalNamingContexts
SYNOPSIS: Gets LDAP path for Schema and Extendend-Rights
ENTRY: pszServerName, Server to bind to for query
EXIT: pszSchemaNamingContext: Schema name in
"LDAP:\\cn=schema,cn=..." format
pszConfigurationNamingContext: Extendend rights path
in "LDAP:\\CN=Extended-Rights,CN=Configuration..formats
RETURNS: WIN32 Error Code
********************************************************************/
DWORD GetGlobalNamingContexts( LPWSTR pszServerName,
LPWSTR * pszSchemaNamingContext,
LPWSTR * pszConfigurationNamingContext )
{
HRESULT hr = S_OK;
DWORD dwErr = ERROR_SUCCESS;
LPWSTR szSNC = NULL;
ULONG uLen = 0;
IADs *spRootDSE = NULL;
LPWSTR pszRootDsePath = NULL;
*pszSchemaNamingContext = NULL;
*pszConfigurationNamingContext = NULL;
if( pszServerName )
uLen = wcslen(L"LDAP://") +
wcslen( pszServerName ) +
wcslen( L"/RootDSE") + 1;
else
uLen = wcslen(L"LDAP://RootDSE");
pszRootDsePath = (LPWSTR)LocalAlloc( LMEM_FIXED, uLen * sizeof(WCHAR) );
CHECK_NULL( pszRootDsePath,FAILURE_RETURN );
wcscpy(pszRootDsePath, L"LDAP://");
if( pszServerName )
{
wcscat( pszRootDsePath, pszServerName );
wcscat( pszRootDsePath, L"/" );
}
wcscat( pszRootDsePath, L"RootDSE" );
/*hr = ::ADsOpenObject( pszRootDsePath,
NULL,
NULL,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)&spRootDSE
);
*/
hr = ::ADsGetObject( pszRootDsePath,
IID_IADs,
(void**)&spRootDSE );
CHECK_HR( hr, FAILURE_RETURN );
VARIANT varSchemaNamingContext;
hr = spRootDSE->Get(L"schemaNamingContext",
&varSchemaNamingContext);
CHECK_HR( hr, FAILURE_RETURN );
szSNC = (LPWSTR)varSchemaNamingContext.bstrVal;
uLen = wcslen( szSNC ) + 8 ; //For "LDAP:// + 1
*pszSchemaNamingContext = (LPWSTR) LocalAlloc( LMEM_FIXED, uLen* sizeof(WCHAR) );
CHECK_NULL( *pszSchemaNamingContext, FAILURE_RETURN );
wcscpy( *pszSchemaNamingContext, L"LDAP://");
wcscat( *pszSchemaNamingContext, szSNC );
hr = spRootDSE->Get(L"configurationNamingContext",
&varSchemaNamingContext);
CHECK_HR( hr, FAILURE_RETURN );
szSNC = (LPWSTR)varSchemaNamingContext.bstrVal;
uLen = wcslen( szSNC ) + 27 + 1 ;
*pszConfigurationNamingContext = (LPWSTR) LocalAlloc( LMEM_FIXED, uLen* sizeof(WCHAR) );
CHECK_NULL( *pszConfigurationNamingContext,FAILURE_RETURN );
wcscpy( *pszConfigurationNamingContext, L"LDAP://CN=Extended-Rights,");
wcscat( *pszConfigurationNamingContext, szSNC );
goto SUCCESS_RETURN;
FAILURE_RETURN:
if( *pszSchemaNamingContext )
LocalFree( *pszSchemaNamingContext );
if( *pszConfigurationNamingContext )
LocalFree( *pszConfigurationNamingContext );
SUCCESS_RETURN:
if( spRootDSE )
spRootDSE->Release();
if( pszRootDsePath )
LocalFree( pszRootDsePath );
return dwErr;
}
/*******************************************************************
NAME: FormatStringGUID
SYNOPSIS: Given a GUID struct, it returns a GUID in string format,
without {}
//Function copied from marcoc code
********************************************************************/
BOOL FormatStringGUID(LPWSTR lpszBuf, UINT nBufSize, const GUID* pGuid)
{
lpszBuf[0] = NULL;
// if it is a NULL GUID*, just return an empty string
if (pGuid == NULL)
{
return FALSE;
}
/*
typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[ 8 ];
}
int _snwprintf( wchar_t *buffer, size_t count, const wchar_t *format [, argume
nt] ... );
*/
return (_snwprintf(lpszBuf, nBufSize,
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
pGuid->Data1, pGuid->Data2, pGuid->Data3,
pGuid->Data4[0], pGuid->Data4[1],
pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5],
pGuid->Data4[6], pGuid->Data4[7]) > 0);
}
/*
Returns A string with n spaces
*/
void StringWithNSpace( UINT n, LPWSTR szSpace )
{
for( UINT i = 0; i < n ; ++ i )
szSpace[i] = L' ';
szSpace[n] = 0;
}
/*
Loads the string from Resource Table and
Formats it
*/
DWORD
LoadMessage( IN DWORD MessageId, LPWSTR *ppszLoadString,...)
{
va_list ArgList;
DWORD dwErr = ERROR_SUCCESS;
va_start( ArgList, ppszLoadString );
WCHAR szBuffer[1024];
if( LoadString( g_hInstance,
MessageId,
szBuffer,
1023 ) == 0 )
{
dwErr = GetLastError();
goto CLEAN_RETURN;
}
if( FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
szBuffer,
MessageId,
0,
( PWSTR )ppszLoadString,
0,
&ArgList ) == 0 )
{
dwErr = GetLastError();
goto CLEAN_RETURN;
}
CLEAN_RETURN:
va_end( ArgList );
return dwErr;
}
/*******************************************************************
NAME: DisplayString
SYNOPSIS: Displays a string after inserting nIdent spaces
********************************************************************/
VOID DisplayString( UINT nIdent, LPWSTR pszDisplay )
{
for ( UINT i = 0; i < nIdent; i++ )
wprintf( L" " );
wprintf(L"%s",pszDisplay);
}
VOID DisplayStringWithNewLine( UINT nIdent, LPWSTR pszDisplay )
{
DisplayString( nIdent, pszDisplay );
wprintf(L"\n");
}
VOID DisplayNewLine()
{
wprintf(L"\n");
}
/*******************************************************************
NAME: DisplayMessageEx
SYNOPSIS: Loads Message from Resource and Formats its
IN Indent - Number of tabs to indent
MessageId - Id of the message to load
... - Optional list of parameters
RETURNS: NONE
********************************************************************/
DWORD
DisplayMessageEx( DWORD nIndent, IN DWORD MessageId,...)
{
va_list ArgList;
LPWSTR pszLoadString = NULL;
va_start( ArgList, MessageId );
WCHAR szBuffer[1024];
if( LoadString( g_hInstance,
MessageId,
szBuffer,
1023 ) == 0 )
{
va_end( ArgList );
return GetLastError();
}
if( FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
szBuffer,
MessageId,
0,
( PWSTR )&pszLoadString,
0,
&ArgList ) == 0 )
{
va_end( ArgList );
return GetLastError();
}
DisplayStringWithNewLine( nIndent, pszLoadString );
LocalFree( pszLoadString );
return ERROR_SUCCESS;
}
BOOL GuidFromString(GUID* pGuid, LPCWSTR lpszGuidString)
{
ZeroMemory(pGuid, sizeof(GUID));
if (lpszGuidString == NULL)
{
return FALSE;
}
int nLen = lstrlen(lpszGuidString);
// the string length should be 36
if (nLen != 36)
return FALSE;
// add the braces to call the Win32 API
LPWSTR lpszWithBraces = (LPWSTR)LocalAlloc(LMEM_FIXED,((nLen+1+2)*sizeof(WCHAR)) ); // NULL plus {}
if(!lpszWithBraces)
return FALSE;
wsprintf(lpszWithBraces, L"{%s}", lpszGuidString);
return SUCCEEDED(::CLSIDFromString(lpszWithBraces, pGuid));
}
/*******************************************************************
NAME: GetServerName
SYNOPSIS: Get the name of the server. If Obeject Path is in form
\\ADSERVER\CN=John..., then it gets the server name
from Object Path and changes Object Path to CN=John...
********************************************************************/
DWORD GetServerName( IN LPWSTR ObjectPath,
OUT LPWSTR * ppszServerName )
{
DWORD Win32Err = ERROR_SUCCESS;
PWSTR Separator = NULL;
PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
PDOMAIN_CONTROLLER_INFO DcInfo1 = NULL;
PWSTR Path = NULL;
HANDLE DsHandle = NULL;
PDS_NAME_RESULT NameRes = NULL;
BOOLEAN NamedServer = FALSE;
NTSTATUS Status;
LPWSTR ServerName = NULL;
//
// Get a server name
//
if ( wcslen( ObjectPath ) > 2 && *ObjectPath == L'\\' && *( ObjectPath + 1 ) == L'\\' ) {
Separator = wcschr( ObjectPath + 2, L'\\' );
if ( Separator ) {
*Separator = L'\0';
Path = Separator + 1;
}
else
return ERROR_INVALID_PARAMETER;
ServerName = ObjectPath + 2;
*ppszServerName = (LPWSTR)LocalAlloc(LMEM_FIXED,
sizeof(WCHAR) * (wcslen(ServerName) + 1) );
if( *ppszServerName == NULL )
{
if( Separator )
*Separator = L'\\';
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy( *ppszServerName, ServerName );
//Remove server name from object path
memmove( ObjectPath, Path, ( wcslen(Path) + 1) * sizeof(WCHAR) );
return ERROR_SUCCESS;
} else {
Path = ObjectPath;
Win32Err = DsGetDcName( NULL,
NULL,
NULL,
NULL,
DS_DIRECTORY_SERVICE_REQUIRED,
&DcInfo );
if ( Win32Err == ERROR_SUCCESS ) {
ServerName = DcInfo[ 0 ].DomainControllerName + 2;
}
}
//
// Do the bind and crack
//
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = DsBind( ServerName,
NULL,
&DsHandle );
if ( Win32Err == ERROR_SUCCESS ) {
Win32Err = DsCrackNames( DsHandle,
DS_NAME_NO_FLAGS,
DS_FQDN_1779_NAME,
DS_FQDN_1779_NAME,
1,
&Path,
&NameRes );
if ( Win32Err == ERROR_SUCCESS ) {
if ( NameRes->cItems != 0 &&
NameRes->rItems[ 0 ].status == DS_NAME_ERROR_DOMAIN_ONLY ) {
Win32Err = DsGetDcNameW( NULL,
NameRes->rItems[ 0 ].pDomain,
NULL,
NULL,
DS_DIRECTORY_SERVICE_REQUIRED,
&DcInfo1 );
if ( Win32Err == ERROR_SUCCESS ) {
ServerName = DcInfo1->DomainControllerName + 2;
}
if( Win32Err == ERROR_INVALID_DOMAINNAME ||
Win32Err == ERROR_NO_SUCH_DOMAIN )
ServerName = NULL;
}
}
}
}
if( ServerName )
{
*ppszServerName = (LPWSTR)LocalAlloc(LMEM_FIXED,
sizeof(WCHAR) * (wcslen(ServerName) + 1) );
if( *ppszServerName == NULL )
return ERROR_NOT_ENOUGH_MEMORY;
wcscpy( *ppszServerName, ServerName );
Win32Err = ERROR_SUCCESS;
}
if( DcInfo )
NetApiBufferFree( DcInfo );
if( DcInfo1 )
NetApiBufferFree( DcInfo1 );
if( DsHandle )
DsUnBindW( &DsHandle );
if ( NameRes )
DsFreeNameResult( NameRes );
return Win32Err;
}
/*******************************************************************
NAME: DisplayMessage
SYNOPSIS: Loads Message from Message Table and Formats its
IN Indent - Number of tabs to indent
MessageId - Id of the message to load
... - Optional list of parameters
RETURNS: NONE
********************************************************************/
VOID
DisplayMessage(
IN DWORD Indent,
IN DWORD MessageId,
...
)
/*++
Routine Description:
Loads the resource out of the executable and displays it.
Arguments:
Indent - Number of tabs to indent
MessageId - Id of the message to load
... - Optional list of parameters
Return Value:
VOID
--*/
{
PWSTR MessageDisplayString;
va_list ArgList;
ULONG Length, i;
va_start( ArgList, MessageId );
Length = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
MessageId,
0,
( PWSTR )&MessageDisplayString,
0,
&ArgList );
if ( Length != 0 ) {
for ( i = 0; i < Indent; i++ ) {
printf( "\t" );
}
printf( "%ws", MessageDisplayString );
LocalFree( MessageDisplayString );
}
va_end( ArgList );
}
/*******************************************************************
NAME: DisplayErrorMessage
SYNOPSIS: Displays Error Message corresponding to Error
RETURNS: NONE
********************************************************************/
VOID
DisplayErrorMessage(
IN DWORD Error
)
{
ULONG Size = 0;
PWSTR DisplayString;
ULONG Options = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
Size = FormatMessage( Options,
NULL,
Error,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
( LPTSTR )&DisplayString,
0,
NULL );
if ( Size != 0 ) {
printf( "%ws\n", DisplayString );
LocalFree( DisplayString );
}
}
/*******************************************************************
NAME: ConvertStringAToStringW
SYNOPSIS: Converts MBYTE stirng to UNICODE
RETURNS: ERROR_SUCCESS if success
ERROR_NOT_ENOUGH_MEMORY
********************************************************************/
DWORD
ConvertStringAToStringW (
IN PSTR AString,
OUT PWSTR *WString
)
{
DWORD Win32Err = ERROR_SUCCESS, Length;
if ( AString == NULL ) {
*WString = NULL;
} else {
Length = strlen( AString );
*WString = ( PWSTR )LocalAlloc( LMEM_FIXED,
( mbstowcs( NULL, AString, Length + 1 ) + 1 ) *
sizeof( WCHAR ) );
if(*WString != NULL ) {
mbstowcs( *WString, AString, Length + 1);
} else {
Win32Err = ERROR_NOT_ENOUGH_MEMORY;
}
}
return( Win32Err );
}
/*******************************************************************
NAME: CopyUnicodeString
SYNOPSIS: Copy Unicode string from Source to Destination
RETURNS: ERROR_SUCCESS if success
ERROR_NOT_ENOUGH_MEMORY
********************************************************************/
DWORD CopyUnicodeString( LPWSTR * strDst, LPWSTR strSrc )
{
*strDst = (LPWSTR)LocalAlloc( LMEM_FIXED , ( wcslen(strSrc) + 1 ) * sizeof(WCHAR ) );
if ( !*strDst ) {
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy( *strDst, strSrc );
return ERROR_SUCCESS;
}
/*******************************************************************
NAME: GetProtection
SYNOPSIS: Sets PROTECTED_DACL_SECURITY_INFORMATION in pSI,
if SE_DACL_PROTECTED is set pSD
RETURNS: ERROR_SUCCESS if success
********************************************************************/
DWORD GetProtection( PSECURITY_DESCRIPTOR pSD, SECURITY_INFORMATION * pSI )
{
SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
DWORD dwRevision;
//
;
if( !GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision) )
{
return GetLastError();
}
if ( wSDControl & SE_DACL_PROTECTED )
*pSI |= PROTECTED_DACL_SECURITY_INFORMATION;
return ERROR_SUCCESS;
}
/*******************************************************************
NAME: BuildLdapPath
SYNOPSIS: Builds a LDAP path using servername and path
RETURNS: ERROR_SUCCESS if success
********************************************************************/
DWORD BuildLdapPath( LPWSTR * ppszLdapPath,
LPWSTR pszServerName,
LPWSTR pszPath )
{
ULONG uLen = 0;
if( pszServerName )
uLen = wcslen( pszServerName ) + wcslen( pszPath );
else
uLen = wcslen( pszPath );
uLen += 9; //LDAP://ServerName/path
*ppszLdapPath = (LPWSTR)LocalAlloc( LMEM_FIXED, uLen * sizeof(WCHAR) );
if( NULL == *ppszLdapPath )
return ERROR_NOT_ENOUGH_MEMORY;
wcscpy( * ppszLdapPath, L"LDAP://" );
if( pszServerName )
{
wcscat( * ppszLdapPath, pszServerName );
wcscat( * ppszLdapPath, L"/");
}
wcscat(* ppszLdapPath, pszPath );
return ERROR_SUCCESS;
}