windows-nt/Source/XPSP1/NT/ds/security/ntmarta/newsrc/dsctx.cpp
2020-09-26 16:20:57 +08:00

968 lines
24 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// File: dsctx.cpp
//
// Contents: Implementation of CDsObjectContext and NT Marta DS object
// Functions
//
// History: 3-31-1999 kirtd Created
//
//----------------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
#include <windows.h>
#include <dsctx.h>
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::CDsObjectContext, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CDsObjectContext::CDsObjectContext ()
{
m_cRefs = 1;
memset( &m_LdapUrlComponents, 0, sizeof( m_LdapUrlComponents ) );
m_pBinding = NULL;
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::~CDsObjectContext, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CDsObjectContext::~CDsObjectContext ()
{
LdapFreeBindings( m_pBinding );
LdapFreeUrlComponents( &m_LdapUrlComponents );
assert( m_cRefs == 0 );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::InitializeByName, public
//
// Synopsis: initialize the context given the name of the lanman share
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::InitializeByName (LPCWSTR pObjectName, ACCESS_MASK AccessMask)
{
DWORD Result = ERROR_SUCCESS;
LPWSTR pwszName = NULL;
ULONG len = wcslen( pObjectName );
ULONG i, j;
if ( _wcsnicmp( pObjectName, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) != 0 )
{
pwszName = new WCHAR [ len + wcslen( LDAP_SCHEME_UC ) + 2 ];
if ( pwszName != NULL )
{
wcscpy( pwszName, LDAP_SCHEME_UC );
wcscat( pwszName, L"/" );
wcscat( pwszName, pObjectName );
}
else
{
Result = ERROR_OUTOFMEMORY;
}
}
else
{
pwszName = new WCHAR [ len + 1 ];
if ( pwszName != NULL )
{
wcscpy( pwszName, pObjectName );
}
else
{
Result = ERROR_OUTOFMEMORY;
}
}
if ( Result == ERROR_SUCCESS )
{
for (i = j = 0; i <= len; i++, j++)
{
if (L'\\' == pwszName[i])
{
if (L'/' != pwszName[i+1])
{
pwszName[j++] = pwszName[i++];
}
else
{
i++;
}
}
pwszName[j] = pwszName[i];
}
}
if ( Result == ERROR_SUCCESS )
{
if ( LdapCrackUrl( pwszName, &m_LdapUrlComponents ) == FALSE )
{
Result = GetLastError();
}
}
if ( Result == ERROR_SUCCESS )
{
if ( LdapGetBindings(
m_LdapUrlComponents.pwszHost,
m_LdapUrlComponents.Port,
0,
0,
&m_pBinding
) == FALSE )
{
Result = GetLastError();
}
}
if ( pwszName != pObjectName )
{
delete pwszName;
}
return( Result );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::AddRef, public
//
// Synopsis: add a reference to the context
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::AddRef ()
{
m_cRefs += 1;
return( m_cRefs );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::Release, public
//
// Synopsis: release a reference to the context
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::Release ()
{
m_cRefs -= 1;
if ( m_cRefs == 0 )
{
delete this;
return( 0 );
}
return( m_cRefs );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::GetDsObjectProperties, public
//
// Synopsis: get properties about the context
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::GetDsObjectProperties (
PMARTA_OBJECT_PROPERTIES pObjectProperties
)
{
if ( pObjectProperties->cbSize < sizeof( MARTA_OBJECT_PROPERTIES ) )
{
return( ERROR_INVALID_PARAMETER );
}
assert( pObjectProperties->dwFlags == 0 );
return( ERROR_SUCCESS );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::GetDsObjectRights, public
//
// Synopsis: get the DsObject security descriptor
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::GetDsObjectRights (
SECURITY_INFORMATION SecurityInfo,
PSECURITY_DESCRIPTOR* ppSecurityDescriptor
)
{
DWORD Result;
Result = MartaReadDSObjSecDesc(
m_pBinding,
m_LdapUrlComponents.pwszDN,
SecurityInfo,
ppSecurityDescriptor
);
return( Result );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::SetDsObjectRights, public
//
// Synopsis: set the window security descriptor
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::SetDsObjectRights (
SECURITY_INFORMATION SecurityInfo,
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
DWORD Result;
PISECURITY_DESCRIPTOR pisd = NULL;
DWORD cb = 0;
PSECURITY_DESCRIPTOR psd = NULL;
pisd = (PISECURITY_DESCRIPTOR)pSecurityDescriptor;
if ( pisd->Control & SE_SELF_RELATIVE )
{
cb = GetSecurityDescriptorLength( pSecurityDescriptor );
psd = pSecurityDescriptor;
}
else
{
if ( MakeSelfRelativeSD(
pSecurityDescriptor,
NULL,
&cb
) == FALSE )
{
if ( cb > 0 )
{
psd = new BYTE [ cb ];
if ( psd != NULL )
{
if ( MakeSelfRelativeSD(
pSecurityDescriptor,
psd,
&cb
) == FALSE )
{
delete psd;
return( GetLastError() );
}
}
else
{
return( ERROR_OUTOFMEMORY );
}
}
else
{
return( GetLastError() );
}
}
else
{
assert( FALSE && "Should not get here!" );
return( ERROR_INVALID_PARAMETER );
}
}
assert( psd != NULL );
Result = MartaStampSD(
m_LdapUrlComponents.pwszDN,
cb,
SecurityInfo,
psd,
m_pBinding
);
if ( psd != pSecurityDescriptor )
{
delete psd;
}
return( Result );
}
//+---------------------------------------------------------------------------
//
// Member: CDsObjectContext::GetDsObjectGuid, public
//
// Synopsis: get the object GUID
//
//----------------------------------------------------------------------------
DWORD
CDsObjectContext::GetDsObjectGuid (GUID* pGuid)
{
return( ERROR_INVALID_PARAMETER );
}
//
// Functions from Ds.h which dispatch unto the CDsObjectContext class
//
DWORD
MartaAddRefDsObjectContext(
IN MARTA_CONTEXT Context
)
{
return( ( (CDsObjectContext *)Context )->AddRef() );
}
DWORD
MartaCloseDsObjectContext(
IN MARTA_CONTEXT Context
)
{
return( ( (CDsObjectContext *)Context )->Release() );
}
DWORD
MartaGetDsObjectProperties(
IN MARTA_CONTEXT Context,
IN OUT PMARTA_OBJECT_PROPERTIES pProperties
)
{
return( ( (CDsObjectContext *)Context )->GetDsObjectProperties( pProperties ) );
}
DWORD
MartaGetDsObjectTypeProperties(
IN OUT PMARTA_OBJECT_TYPE_PROPERTIES pProperties
)
{
if ( pProperties->cbSize < sizeof( MARTA_OBJECT_TYPE_PROPERTIES ) )
{
return( ERROR_INVALID_PARAMETER );
}
assert( pProperties->dwFlags == 0 );
pProperties->dwFlags = MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG;
return( ERROR_SUCCESS );
}
DWORD
MartaGetDsObjectRights(
IN MARTA_CONTEXT Context,
IN SECURITY_INFORMATION SecurityInfo,
OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
)
{
return( ( (CDsObjectContext *)Context )->GetDsObjectRights(
SecurityInfo,
ppSecurityDescriptor
) );
}
DWORD
MartaOpenDsObjectNamedObject(
IN LPCWSTR pObjectName,
IN ACCESS_MASK AccessMask,
OUT PMARTA_CONTEXT pContext
)
{
DWORD Result;
CDsObjectContext* pDsObjectContext;
pDsObjectContext = new CDsObjectContext;
if ( pDsObjectContext == NULL )
{
return( ERROR_OUTOFMEMORY );
}
Result = pDsObjectContext->InitializeByName( pObjectName, AccessMask );
if ( Result != ERROR_SUCCESS )
{
pDsObjectContext->Release();
return( Result );
}
*pContext = pDsObjectContext;
return( ERROR_SUCCESS );
}
DWORD
MartaSetDsObjectRights(
IN MARTA_CONTEXT Context,
IN SECURITY_INFORMATION SecurityInfo,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
return( ( (CDsObjectContext *)Context )->SetDsObjectRights(
SecurityInfo,
pSecurityDescriptor
) );
}
DWORD
MartaConvertDsObjectNameToGuid(
IN LPCWSTR pObjectName,
OUT GUID* pGuid
)
{
DWORD Result = ERROR_SUCCESS;
LPWSTR pwszName = NULL;
LDAP_URL_COMPONENTS LdapUrlComponents;
DS_NAME_RESULTW* pnameresult;
HANDLE hDs = NULL;
WCHAR GuidString[ MAX_PATH ];
memset( &LdapUrlComponents, 0, sizeof( LdapUrlComponents ) );
if ( _wcsnicmp( pObjectName, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) != 0 )
{
pwszName = new WCHAR [ wcslen( pObjectName ) +
wcslen( LDAP_SCHEME_U ) + 2 ];
if ( pwszName != NULL )
{
wcscpy( pwszName, LDAP_SCHEME_U );
wcscat( pwszName, L"/" );
wcscat( pwszName, pObjectName );
}
else
{
Result = ERROR_OUTOFMEMORY;
}
}
else
{
pwszName = (LPWSTR)pObjectName;
}
if ( Result == ERROR_SUCCESS )
{
if ( LdapCrackUrl( pwszName, &LdapUrlComponents ) == FALSE )
{
Result = GetLastError();
}
}
if ( Result == ERROR_SUCCESS )
{
Result = DsBindW( LdapUrlComponents.pwszHost, NULL, &hDs );
}
if ( Result == ERROR_SUCCESS )
{
Result = DsCrackNamesW(
hDs,
DS_NAME_NO_FLAGS,
DS_FQDN_1779_NAME,
DS_UNIQUE_ID_NAME,
1,
&LdapUrlComponents.pwszDN,
&pnameresult
);
}
if ( Result == ERROR_SUCCESS )
{
if ( ( pnameresult->cItems > 0 ) &&
( pnameresult->rItems[0].status == ERROR_SUCCESS ) )
{
Result = IIDFromString( pnameresult->rItems[0].pName, pGuid );
}
else
{
Result = ERROR_INVALID_PARAMETER;
}
DsFreeNameResultW( pnameresult );
}
if ( hDs != NULL )
{
DsUnBindW( &hDs );
}
LdapFreeUrlComponents( &LdapUrlComponents );
if ( pwszName != pObjectName )
{
delete pwszName;
}
return( Result );
}
DWORD
MartaConvertGuidToDsName(
IN GUID Guid,
OUT LPWSTR * ppObjectName
)
{
DWORD Result;
HANDLE hDs = NULL;
WCHAR GuidString[ MAX_PATH ];
DS_NAME_RESULTW* pnameresult = NULL;
LPWSTR pObjectName = NULL;
if ( StringFromGUID2( Guid, GuidString, MAX_PATH ) == 0 )
{
return( ERROR_INVALID_PARAMETER );
}
Result = DsBindW( NULL, NULL, &hDs );
if ( Result == ERROR_SUCCESS )
{
Result = DsCrackNamesW(
hDs,
DS_NAME_NO_FLAGS,
DS_UNIQUE_ID_NAME,
DS_FQDN_1779_NAME,
1,
(LPCWSTR *)&GuidString,
&pnameresult
);
}
if ( Result == ERROR_SUCCESS )
{
if ( ( pnameresult->cItems > 0 ) &&
( pnameresult->rItems[0].status == ERROR_SUCCESS ) )
{
pObjectName = (LPWSTR)LocalAlloc(
LPTR,
( wcslen( pnameresult->rItems[0].pName )
+ 1 ) * sizeof( WCHAR )
);
if ( pObjectName != NULL )
{
wcscpy( pObjectName, pnameresult->rItems[0].pName );
*ppObjectName = pObjectName;
}
else
{
Result = ERROR_OUTOFMEMORY;
}
}
else
{
Result = ERROR_INVALID_PARAMETER;
}
DsFreeNameResultW( pnameresult );
}
if ( hDs != NULL )
{
DsUnBindW( &hDs );
}
return( ERROR_SUCCESS );
}
//+---------------------------------------------------------------------------
//
// Function: MartaReadDSObjSecDesc
//
// Synopsis: Reads the security descriptor from the specied object via
// the open ldap connection
//
// Arguments: [IN pLDAP] -- The open LDAP connection
// [IN SeInfo] -- Parts of the security descriptor to
// read.
// [IN pwszDSObj] -- The DSObject to get the security
// descriptor for
// [OUT ppSD] -- Where the security descriptor is
// returned
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
// Notes: The returned security descriptor must be freed with LocalFree
//
//----------------------------------------------------------------------------
DWORD
MartaReadDSObjSecDesc(IN PLDAP pLDAP,
IN LPWSTR pwszObject,
IN SECURITY_INFORMATION SeInfo,
OUT PSECURITY_DESCRIPTOR *ppSD)
{
DWORD dwErr = ERROR_SUCCESS;
PLDAPMessage pMessage = NULL;
LPWSTR rgAttribs[2];
BYTE berValue[8];
//
// JohnsonA The BER encoding is current hardcoded. Change this to use
// AndyHe's BER_printf package once it's done.
//
berValue[0] = 0x30;
berValue[1] = 0x03;
berValue[2] = 0x02;
berValue[3] = 0x01;
berValue[4] = (BYTE)((ULONG)SeInfo & 0xF);
LDAPControlW SeInfoControl =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, (PCHAR)berValue
},
TRUE
};
PLDAPControlW ServerControls[2] =
{
&SeInfoControl,
NULL
};
rgAttribs[0] = SD_PROP_NAME;
rgAttribs[1] = NULL;
if(dwErr == ERROR_SUCCESS)
{
dwErr = ldap_search_ext_sW(pLDAP,
pwszObject,
LDAP_SCOPE_BASE,
L"(objectClass=*)",
rgAttribs,
0,
(PLDAPControlW *)&ServerControls,
NULL,
NULL,
10000,
&pMessage);
dwErr = LdapMapErrorToWin32( dwErr );
}
if(dwErr == ERROR_SUCCESS)
{
LDAPMessage *pEntry = NULL;
pEntry = ldap_first_entry(pLDAP,pMessage);
if(pEntry == NULL)
{
dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_ACCESS_DENIED;
}
else
{
PLDAP_BERVAL *pSize = ldap_get_values_lenW(pLDAP,
pMessage,
rgAttribs[0]);
if(pSize == NULL)
{
dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
}
else
{
//
// Allocate the security descriptor to return
//
*ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, (*pSize)->bv_len);
if(*ppSD == NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
memcpy(*ppSD, (PBYTE)(*pSize)->bv_val, (*pSize)->bv_len);
}
ldap_value_free_len(pSize);
}
}
}
if ( pMessage != NULL )
{
ldap_msgfree(pMessage);
}
return(dwErr);
}
//+---------------------------------------------------------------------------
//
// Function: MartaStampSD
//
// Synopsis: Actually stamps the security descriptor on the object.
//
// Arguments: [IN pwszObject] -- The object to stamp the SD on
// [IN cSDSize] -- The size of the security descriptor
// [IN SeInfo] -- SecurityInformation about the security
// descriptor
// [IN pSD] -- The SD to stamp
// [IN pLDAP] -- The LDAP connection to use
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
//
//----------------------------------------------------------------------------
DWORD
MartaStampSD(IN LPWSTR pwszObject,
IN ULONG cSDSize,
IN SECURITY_INFORMATION SeInfo,
IN PSECURITY_DESCRIPTOR pSD,
IN PLDAP pLDAP)
{
DWORD dwErr = ERROR_SUCCESS;
//
// Now, we'll do the write. The security descriptor
// we got passed in better not be in the old Ds format,
// where the leading 4 bytes are the SECURITY_INFORMATION, which we'll skip
// and replace with control information
//
assert(*(PULONG)pSD > 0xF );
PLDAPModW rgMods[2];
PLDAP_BERVAL pBVals[2];
LDAPModW Mod;
LDAP_BERVAL BVal;
BYTE ControlBuffer[ 5 ];
LDAPControlW SeInfoControl =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, (PCHAR) &ControlBuffer
},
TRUE
};
//
// !!! Hardcoded for now. Use Andyhe's BER_printf once it's done.
//
ControlBuffer[0] = 0x30;
ControlBuffer[1] = 0x3;
ControlBuffer[2] = 0x02; // Denotes an integer;
ControlBuffer[3] = 0x01; // Size
ControlBuffer[4] = (BYTE)((ULONG)SeInfo & 0xF);
PLDAPControlW ServerControls[2] =
{
&SeInfoControl,
NULL
};
assert(IsValidSecurityDescriptor( pSD ) );
rgMods[0] = &Mod;
rgMods[1] = NULL;
pBVals[0] = &BVal;
pBVals[1] = NULL;
BVal.bv_len = cSDSize;
BVal.bv_val = (PCHAR)pSD;
Mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
Mod.mod_type = SD_PROP_NAME;
Mod.mod_values = (LPWSTR *)pBVals;
//
// Now, we'll do the write...
//
dwErr = ldap_modify_ext_sW(pLDAP,
pwszObject,
rgMods,
(PLDAPControlW *)&ServerControls,
NULL);
dwErr = LdapMapErrorToWin32(dwErr);
return(dwErr);
}
DWORD
MartaGetDsParentName(
IN LPWSTR ObjectName,
OUT LPWSTR *pParentName
)
/*++
Routine Description:
Given the name of a DS object return the name of its parent. The routine
allocates memory required to hold the parent name.
Arguments:
ObjectName - Name of the DS object.
pParentName - To return the pointer to the allocated parent name.
In case of the root of the tree, we return NULL parent with ERROR_SUCCESS.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
LPCWSTR pKey = NULL;
LPCWSTR pVal = NULL;
DWORD ccKey = 0;
DWORD ccDN = 0;
DWORD ccVal = 0;
DWORD Size = 0;
DWORD dwErr = ERROR_SUCCESS;
LPCWSTR pDN = (LPWSTR) ObjectName;
ccDN = wcslen(pDN);
*pParentName = NULL;
//
// The input is empty. There is no parent. Just return.
//
if (0 == ccDN)
{
return ERROR_SUCCESS;
}
//
// Do the first pass to get to the next level. At the end of this call,
// pDN will point to the next ','. One more call to DsGetRdnW will
// return the right result in pKey.
// Input:
// pDN = "CN=Kedar, DC=NTDEV, DC=Microsoft, DC=com"
// Output:
// pDN = ", DC=NTDEV, DC=Microsoft, DC=com"
//
dwErr = DsGetRdnW(
&pDN,
&ccDN,
&pKey,
&ccKey,
&pVal,
&ccVal
);
if (ERROR_SUCCESS != dwErr)
{
return dwErr;
}
//
// This is TRUE when the Object does not have any parent.
//
if (0 == ccDN)
{
return ERROR_SUCCESS;
}
//
// Input:
// pDN = ", DC=NTDEV, DC=Microsoft, DC=com"
// Output:
// pKey = "DC=NTDEV, DC=Microsoft, DC=com"
//
dwErr = DsGetRdnW(
&pDN,
&ccDN,
&pKey,
&ccKey,
&pVal,
&ccVal
);
if (ERROR_SUCCESS != dwErr)
{
return dwErr;
}
//
// We have to distinguish between LDAP://ServerName/ObjectName and
// ObjectName.
//
if (!_wcsnicmp(ObjectName, LDAP_SCHEME_U, wcslen(LDAP_SCHEME_U)) != 0 )
{
ULONG HostSize;
//
// Compute the size of string required to hold "LDAP//ServerName/" in
// HostSize.
//
pDN = ObjectName + sizeof("ldap://");
pDN = wcschr(pDN, L'/');
if (NULL == pDN)
{
return ERROR_INVALID_PARAMETER;
}
HostSize = (ULONG) (pDN - ObjectName + 1);
Size = (1 + wcslen(pKey) + HostSize) * sizeof(WCHAR);
*pParentName = (LPWSTR) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, Size);
if (NULL == *pParentName)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy the name of the parent into allocated memeory.
//
wcsncpy(*pParentName, ObjectName, HostSize);
wcscpy((*pParentName) + HostSize, pKey);
}
else
{
Size = (1 + wcslen(pKey)) * sizeof(WCHAR);
*pParentName = (LPWSTR) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, Size);
if (NULL == *pParentName)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Copy the name of the parent into allocated memeory.
//
wcscpy(*pParentName, pKey);
}
return ERROR_SUCCESS;
}