WindowsXP-SP1/ds/adsi/router/cadssec.cxx

1798 lines
45 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: cadssec.cxx
//
// Contents: This file contains the support ADsSecurityUtility class
// implementation and the support routines it requires. The
// default interface for the ADsSecurityClassUtility class
// is IADsSecurityUtility.
//
// History: 10-11-00 AjayR Created.
//
//----------------------------------------------------------------------------
#include "oleds.hxx"
//
// Helper functions.
//
//+---------------------------------------------------------------------------
// Function: GetServerAndResource - Helper routine.
//
// Synopsis: Splits the string into a serverName piece and rest piece.
// This is used for fileshare paths like \\Computer\share to return
// \\computer and share. In the case of registry a string like
// \\Computer\HKLM\Microsoft will be split into \\Computer and
// HKLM\Microsoft. if there is no computer name specified, then
// the serverName will be NULL.
//
// Arguments: pszName - Name to be split.
// ppszServer - Return value for server name.
// ppszResource - Return value for rest of string.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: ppSD and pdwLength on success.
//
//----------------------------------------------------------------------------
HRESULT
GetServerAndResource(
LPWSTR pszName,
LPWSTR *ppszServer,
LPWSTR *ppszResource
)
{
HRESULT hr = S_OK;
DWORD dwLength = wcslen(pszName);
LPWSTR pszTemp = pszName;
LPWSTR pszServer = NULL;
LPWSTR pszResource = NULL;
DWORD dwLen = 0;
BOOL fNoServer = FALSE;
*ppszServer = NULL;
*ppszResource = NULL;
//
// If we have just 1 \ or no \'s there is no server name.
//
if ((dwLength < 2)
|| (pszName[0] != L'\\')
|| (pszName[1] != L'\\')
) {
fNoServer = TRUE;
}
if (fNoServer) {
//
// Name is the entire string passed in.
//
pszResource = AllocADsStr(pszName);
if (!pszResource) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
*ppszResource = pszResource;
RRETURN(hr);
}
//
// Make sure that the first 2 chars are \\
//
if (pszTemp[0] != L'\\'
|| pszTemp[1] != L'\\' )
{
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
pszTemp += 2;
while (pszTemp && *pszTemp != L'\\') {
dwLen++;
pszTemp++;
}
if (!pszTemp
|| !*pszTemp
|| !dwLen
) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
dwLen += 2; // the 2 \\ in the serverName
//
// Advance past the \ in \\testShare\FileShare.
//
pszTemp++;
if (!pszTemp || !*pszTemp) {
BAIL_ON_FAILURE(hr = E_INVALIDARG)
}
//
// If we get here we have valid server and share names.
//
pszServer = (LPWSTR) AllocADsMem((dwLen+1) * sizeof(WCHAR));
if (!pszServer) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
wcsncpy(pszServer, pszName, dwLen);
pszResource = AllocADsStr(pszTemp);
if (!pszResource) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
*ppszServer = pszServer;
*ppszResource = pszResource;
error:
if (FAILED(hr)) {
if (pszResource) {
FreeADsMem(pszResource);
}
if (pszServer) {
FreeADsMem(pszServer);
}
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetKeyRootAndSubKey - Helper routine.
//
// Synopsis: Gets the root (such as HKLM) from the registry key path. This
// is needed when we open a handle to the key. The rest of the path
// constitutes the SubKey name.
//
// Arguments: pszKeyName - Name of the key we need to open.
// ppszSubKey - Return value for the subKey
// phKey - Return value for key root to open.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: phKey, NULL on failure and one of
// HKEY_USERS, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG,
// HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT
// or HKEY_PERFORMANCE_DATA on success.
//
//----------------------------------------------------------------------------
HRESULT
GetKeyRootAndSubKey(
LPWSTR pszKeyName,
LPWSTR * ppszSubKey,
HKEY * phKey
)
{
HRESULT hr = S_OK;
HKEY hKey = NULL;
LPWSTR pszRoot = NULL;
LPWSTR pszTemp = pszKeyName;
LPWSTR pszSubKey = NULL;
DWORD dwLen = 0;
*phKey = NULL;
*ppszSubKey = NULL;
while (pszTemp
&& *pszTemp
&& *pszTemp != L'\\') {
dwLen++;
pszTemp++;
}
//
// If the length is less than 3 something is wrong.
//
if ((dwLen < 3)
|| !pszTemp
|| !*pszTemp
) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
//
// To get the subkey, we need to move past the \.
//
pszTemp++;
if (pszTemp && *pszTemp) {
pszSubKey = AllocADsStr(pszTemp);
if (!pszSubKey) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
pszRoot = (LPWSTR) AllocADsMem((dwLen+1) * sizeof(WCHAR));
if (!pszRoot) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Copy over the root so we can use it in the subsequent comparisions.
//
wcsncpy(pszRoot, pszKeyName, dwLen);
if (_wcsicmp( pszRoot, L"HKEY_CLASSES_ROOT") == 0
|| _wcsicmp( pszRoot, L"HKCR") == 0
) {
hKey = HKEY_CLASSES_ROOT;
}
else if (_wcsicmp( pszRoot, L"HKEY_LOCAL_MACHINE") == 0
|| _wcsicmp( pszRoot, L"HKLM") == 0
) {
hKey = HKEY_LOCAL_MACHINE;
}
else if (_wcsicmp(pszRoot, L"HKEY_CURRENT_CONFIG") == 0
|| _wcsicmp(pszRoot, L"HKCC") == 0
) {
hKey = HKEY_CURRENT_CONFIG;
}
else if (_wcsicmp(pszRoot, L"HKEY_CURRENT_USER" ) == 0
|| _wcsicmp( pszRoot, L"HKCU") == 0
) {
hKey = HKEY_CURRENT_USER;
}
else if (_wcsicmp(pszRoot, L"HKEY_USERS") == 0
|| _wcsicmp(pszRoot, L"HKU")
) {
hKey = HKEY_USERS;
}
else if ( _wcsicmp(pszRoot, L"HKEY_PERFORMANCE_DATA") == 0) {
hKey = HKEY_PERFORMANCE_DATA;
}
else {
//
// Has to be one of the above.
//
BAIL_ON_FAILURE(hr = E_FAIL);
}
*phKey = hKey;
*ppszSubKey = pszSubKey;
error:
if (pszRoot) {
FreeADsStr(pszRoot);
}
if (FAILED(hr) && pszSubKey) {
FreeADsStr(pszSubKey);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertRawSDToBinary - Helper routine.
//
// Synopsis: Converts the binary SD to a VT_UI1 | VT_ARRAY.
//
// Arguments: pSecurityDescriptor - Binary sd to convert.
// dwLength - Length of SD.
// pVariant - Return value.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pVariant to point to IID_IADsSecurityDescriptor on success.
//
//----------------------------------------------------------------------------
HRESULT
ConvertRawSDToBinary(
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD dwLength,
VARIANT *pVariant
)
{
HRESULT hr = S_OK;
SAFEARRAY * aList = NULL;
SAFEARRAYBOUND aBound;
CHAR HUGEP *pArray = NULL;
aBound.lLbound = 0;
aBound.cElements = dwLength;
aList = SafeArrayCreate( VT_UI1, 1, &aBound );
if (!aList) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray );
BAIL_ON_FAILURE(hr);
memcpy( pArray, pSecurityDescriptor, aBound.cElements );
SafeArrayUnaccessData( aList );
V_VT(pVariant) = VT_ARRAY | VT_UI1;
V_ARRAY(pVariant) = aList;
RRETURN(hr);
error:
if ( aList ) {
SafeArrayDestroy( aList );
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertRawSDToHexString - Helper routine.
//
// Synopsis: Converts the binary SD to a VT_BSTR in hex string format.
//
// Arguments: pSecurityDescriptor - Binary sd to convert.
// dwLength - Length of SD.
// pVariant - Return value for VT_BSTR.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pVariant to point to IID_IADsSecurityDescriptor on success.
//
//----------------------------------------------------------------------------
HRESULT
ConvertRawSDToHexString(
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD dwLength,
VARIANT *pVariant
)
{
HRESULT hr = S_OK;
LPWSTR pszHexStr = NULL;
BSTR bstrHexSD = NULL;
WCHAR szSmallStr[10];
pszHexStr = (LPWSTR) AllocADsMem((dwLength+1) * 2 * sizeof(WCHAR));
if (!pszHexStr) {
BAIL_ON_FAILURE(hr);
}
for (DWORD dwCtr = 0; dwCtr < dwLength; dwCtr++) {
wsprintf(
szSmallStr,
L"%02x",
((BYTE*)pSecurityDescriptor)[dwCtr]
);
wcscat(pszHexStr, szSmallStr);
}
hr = ADsAllocString(pszHexStr, &bstrHexSD);
if (SUCCEEDED(hr)) {
pVariant->vt = VT_BSTR;
pVariant->bstrVal = bstrHexSD;
}
error:
if (pszHexStr) {
FreeADsMem(pszHexStr);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertHexSDToRawSD - Helper routine.
//
// Synopsis: Converts the hex string SD to a binary SD.
//
// Arguments: pVarHexSD - Variant with hex string.
// ppSecurityDescriptor - Return value for binary SD
// pdwLength - Return value for length of SD.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: ppSecurityDescriptor and pdwLength updated accordingly.
//
//----------------------------------------------------------------------------
HRESULT
ConvertHexSDToRawSD(
PVARIANT pVarHexSD,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
DWORD *pdwLength
)
{
HRESULT hr = S_OK;
LPWSTR pszHexSD = V_BSTR(pVarHexSD);
DWORD dwLen;
LPBYTE lpByte = NULL;
*ppSecurityDescriptor = NULL;
*pdwLength = 0;
if (!pszHexSD
|| ((dwLen = wcslen(pszHexSD)) == 0)
) {
//
// NULL SD.
//
RRETURN(S_OK);
}
dwLen = wcslen(pszHexSD);
//
// Length has to be even.
//
if (((dwLen/2) * 2) != dwLen) {
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
}
dwLen /= 2;
if (dwLen) {
lpByte = (LPBYTE) AllocADsMem(dwLen);
if (!lpByte) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Go through and read one 2 hex chars at a time.
//
for (
DWORD dwCtr = 0;
(dwCtr < dwLen) && (pszHexSD && *pszHexSD);
dwCtr++ ) {
DWORD dwCount, dwHexVal;
dwCount = swscanf(pszHexSD, L"%02x", &dwHexVal);
//
// The read has to be successful and the data valid.
//
if (dwCount != 1) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
//
// Make sure that the value is in the correct range.
//
if (dwHexVal & (0xFFFFFF00)) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
lpByte[dwCtr] = (BYTE) dwHexVal;
pszHexSD++;
if (!pszHexSD) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
pszHexSD++;
} // for loop
//
// The sd translation was succesful.
//
*ppSecurityDescriptor = (PSECURITY_DESCRIPTOR)(LPVOID) lpByte;
*pdwLength = dwLen;
} // if the string had any data in it.
error:
if (FAILED(hr) && lpByte) {
FreeADsMem(lpByte);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ConvertBinarySDToRawSD - Helper routine.
//
// Synopsis: Converts a VT_UI1 | VT_ARRAY to a binary SD.
//
// Arguments: pvVarBinSD - The input variant array to convert.
// ppSecurityDescriptor - Return value for binary sd.
// pdwLength - Return value for length of binary sd.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: ppSecurityDescriptor and pdwLength modified appropriately.
//
//----------------------------------------------------------------------------
HRESULT
ConvertBinarySDToRawSD(
PVARIANT pvVarBinSD,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
DWORD *pdwLength
)
{
HRESULT hr = S_OK;
LPVOID lpMem = NULL;
long lBoundLower = -1;
long lBoundUpper = -1;
CHAR HUGEP *pArray = NULL;
*ppSecurityDescriptor = NULL;
*pdwLength = 0;
//
// Make sure we have an array and then get length.
//
if( pvVarBinSD->vt != (VT_ARRAY | VT_UI1)) {
RRETURN(hr = E_ADS_CANT_CONVERT_DATATYPE);
}
hr = SafeArrayGetLBound(
V_ARRAY(pvVarBinSD),
1,
&lBoundLower
);
BAIL_ON_FAILURE(hr);
hr = SafeArrayGetUBound(
V_ARRAY(pvVarBinSD),
1,
&lBoundUpper
);
BAIL_ON_FAILURE(hr);
if ((lBoundUpper == -1)
&& (lBoundLower == -1)
) {
//
// Nothing further to do in this case.
//
;
}
else {
long lLength;
lLength = (lBoundUpper - lBoundLower) + 1;
lpMem = AllocADsMem(lLength);
if (!lpMem) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = SafeArrayAccessData(
V_ARRAY(pvVarBinSD),
(void HUGEP * FAR *) &pArray
);
BAIL_ON_FAILURE(hr);
memcpy(lpMem, pArray, lLength);
SafeArrayUnaccessData(V_ARRAY(pvVarBinSD));
*ppSecurityDescriptor = (PSECURITY_DESCRIPTOR) lpMem;
*pdwLength = (DWORD) lLength;
}
error:
if (FAILED(hr) && lpMem) {
FreeADsMem(lpMem);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetRawSDFromFile - Helper routine.
//
// Synopsis: Gets the security descriptor from the file in binary format.
//
// Arguments: pszFileName - Name of file to get sd from.
// secInfo - Security mask to use for the operation.
// ppSD - Return value for the SD.
// pdwLength - Return value for the lenght of the SD.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: ppSD and pdwLength on success.
//
//----------------------------------------------------------------------------
HRESULT
GetRawSDFromFile(
LPWSTR pszFileName,
SECURITY_INFORMATION secInfo,
PSECURITY_DESCRIPTOR *ppSD,
PDWORD pdwLength
)
{
HRESULT hr = S_OK;
DWORD dwLength = 0;
PSECURITY_DESCRIPTOR pSD = NULL;
*ppSD = NULL;
*pdwLength = 0;
//
// Get the length of the SD.
//
if (!GetFileSecurity(
pszFileName,
secInfo,
NULL,
0,
&dwLength
)
&& (dwLength == 0)
) {
//
// There was an error.
//
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
}
if (dwLength == 0) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
}
pSD = (PSECURITY_DESCRIPTOR) AllocADsMem(dwLength);
if (!pSD) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
if (!GetFileSecurity(
pszFileName,
secInfo,
pSD,
dwLength,
&dwLength
)
) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
}
*pdwLength = dwLength;
*ppSD = pSD;
error:
if (FAILED(hr) && pSD) {
FreeADsMem(pSD);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: SetRawSDToFile - Helper routine.
//
// Synopsis: Sets the binary security descriptor on the file.
//
// Arguments: pszFileName - Name of file to set sd on.
// secInfo - Security mask to use for the operation.
// pSD - Value of SD to set.
// dwLength - Length of the sd.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
SetRawSDToFile(
LPWSTR pszFileName,
SECURITY_INFORMATION secInfo,
PSECURITY_DESCRIPTOR pSD
)
{
HRESULT hr = S_OK;
if (!SetFileSecurity(
pszFileName,
secInfo,
pSD
)
) {
RRETURN(HRESULT_FROM_WIN32(GetLastError()));
}
else {
RRETURN(S_OK);
}
}
//+---------------------------------------------------------------------------
// Function: GetRawSDFromFileShare - Helper routine.
//
// Synopsis: Gets the security descriptor from the fileshare in bin format.
//
// Arguments: pszFileShareName - Name of fileshare to get sd from.
// ppSD - Return value for the SD.
// pdwLength - Return value for the lenght of the SD.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: ppSD and pdwLength on success.
//
//----------------------------------------------------------------------------
HRESULT
GetRawSDFromFileShare(
LPWSTR pszFileShareName,
PSECURITY_DESCRIPTOR *ppSD,
PDWORD pdwLength
)
{
HRESULT hr = S_OK;
LPWSTR pszServerName = NULL;
LPWSTR pszShareName = NULL;
DWORD dwLength = 0;
PSECURITY_DESCRIPTOR pSD = NULL;
SHARE_INFO_502 * pShareInfo502 = NULL;
NET_API_STATUS nasStatus = NERR_Success;
*ppSD = NULL;
*pdwLength = 0;
//
// We need to split the name into serverName and shareName
//
hr = GetServerAndResource(
pszFileShareName,
&pszServerName,
&pszShareName
);
BAIL_ON_FAILURE(hr);
//
// Only 502 level call returns the SD Info.
//
nasStatus = NetShareGetInfo(
pszServerName,
pszShareName,
502,
(LPBYTE *)&pShareInfo502
);
if (nasStatus != NERR_Success) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
}
//
// If the SD is non NULL process the SD.
//
if (pShareInfo502->shi502_security_descriptor) {
//
// Get the length of the SD, it should not be 0.
//
SetLastError(0);
dwLength = GetSecurityDescriptorLength(
pShareInfo502->shi502_security_descriptor
);
//
// The return length should not be zero.
//
if (dwLength == 0) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
}
pSD = (PSECURITY_DESCRIPTOR) AllocADsMem(dwLength);
if (!pSD) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
memcpy(pSD, pShareInfo502->shi502_security_descriptor, dwLength);
*ppSD = pSD;
*pdwLength = dwLength;
}
else {
//
// The SD was NULL the ret values are set correctly
//
;
}
error:
if (pszServerName) {
FreeADsStr(pszServerName);
}
if (pszShareName) {
FreeADsStr(pszShareName);
}
if (pShareInfo502) {
NetApiBufferFree(pShareInfo502);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: SetRawSDToFileShare - Helper routine.
//
// Synopsis: Sets the binary SD on the fileshare.
//
// Arguments: pszFileShare - Name of fileshare to set sd on.
// pSD - The SD to set.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
SetRawSDToFileShare(
LPWSTR pszFileShare,
PSECURITY_DESCRIPTOR pSD
)
{
HRESULT hr = S_OK;
LPWSTR pszServerName = NULL;
LPWSTR pszShareName = NULL;
SHARE_INFO_502 * pShareInfo502 = NULL;
NET_API_STATUS nasStatus = NERR_Success;
PSECURITY_DESCRIPTOR pTempSD = NULL;
//
// We need to split the name into serverName and shareName
//
hr = GetServerAndResource(
pszFileShare,
&pszServerName,
&pszShareName
);
BAIL_ON_FAILURE(hr);
//
// Ideally we should use 1501 level but that is only on Win2k. So
// we need to read the info, update SD and then set it.
//
nasStatus = NetShareGetInfo(
pszServerName,
pszShareName,
502,
(LPBYTE *) &pShareInfo502
);
if (nasStatus != NERR_Success) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
}
//
// Store away the SD so we restore before free.
//
pTempSD = pShareInfo502->shi502_security_descriptor;
pShareInfo502->shi502_security_descriptor = pSD;
nasStatus = NetShareSetInfo(
pszServerName,
pszShareName,
502,
(LPBYTE) pShareInfo502,
NULL
);
pShareInfo502->shi502_security_descriptor = pTempSD;
if (nasStatus != NERR_Success) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
}
error:
if (pShareInfo502) {
NetApiBufferFree(pShareInfo502);
}
if (pszServerName) {
FreeADsStr(pszServerName);
}
if (pszShareName) {
FreeADsStr(pszShareName);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetRawSDFromRegistry - Helper routine.
//
// Synopsis: Gets the security descriptor from the registry in bin format.
//
// Arguments: pszFileRegKeyName - Name of fileshare to get sd from.
// secInfo - Security mask to use for the operation.
// ppSD - Return value for the SD.
// pdwLength - Return value for the lenght of the SD.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: ppSD and pdwLength on success.
//
//----------------------------------------------------------------------------
HRESULT
GetRawSDFromRegistry(
LPWSTR pszFileRegKeyName,
SECURITY_INFORMATION secInfo,
PSECURITY_DESCRIPTOR *ppSD,
PDWORD pdwLength
)
{
HRESULT hr;
LPWSTR pszServerName = NULL;
LPWSTR pszKeyName = NULL;
LPWSTR pszSubKey = NULL;
DWORD dwLength = 0;
DWORD dwErr;
PSECURITY_DESCRIPTOR pSD = NULL;
HKEY hKey = NULL;
HKEY hKeyRoot = NULL;
HKEY hKeyMachine = NULL;
*ppSD = NULL;
*pdwLength = 0;
//
// We need to split the name into serverName and shareName
//
hr = GetServerAndResource(
pszFileRegKeyName,
&pszServerName,
&pszKeyName
);
BAIL_ON_FAILURE(hr);
//
// pszKeyName has to have a valid string. We need to process it
// to find out which key set we need to open (such as HKLM).
//
hr = GetKeyRootAndSubKey(pszKeyName, &pszSubKey, &hKeyRoot);
BAIL_ON_FAILURE(hr);
//
// Need to open the hKeyRoot on the appropriate machine.
// If the serverName is NULL it will be local machine.
//
dwErr = RegConnectRegistry(
pszServerName,
hKeyRoot,
&hKeyMachine
);
if (dwErr) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
//
// Open the key and try and read the security descriptor
//
dwErr = RegOpenKeyEx(
hKeyMachine,
pszSubKey,
0,
KEY_READ,
&hKey
);
if (dwErr) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
dwErr = RegGetKeySecurity(
hKey,
secInfo,
pSD,
&dwLength
);
if (dwLength == 0) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
pSD = (PSECURITY_DESCRIPTOR) AllocADsMem(dwLength);
if (!pSD) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
dwErr = RegGetKeySecurity(
hKey,
secInfo,
pSD,
&dwLength
);
if (dwErr) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
*ppSD = pSD;
*pdwLength = dwLength;
error:
if (pszServerName) {
FreeADsStr(pszServerName);
}
if (pszKeyName) {
FreeADsStr(pszKeyName);
}
if (pszSubKey) {
FreeADsStr(pszSubKey);
}
if (hKey) {
RegCloseKey(hKey);
}
if (hKeyMachine) {
RegCloseKey(hKeyMachine);
}
if (FAILED(hr) && pSD) {
FreeADsMem(pSD);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: SetRawSDToRegistry - Helper routine.
//
// Synopsis: Sets the security descriptor to the specified key.
//
// Arguments: pszFileRegKeyName - Name of fileshare to set sd on.
// secInfo - Security mask to use for the operation.
// pSD - SD to set on the reg key.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
SetRawSDToRegistry(
LPWSTR pszFileRegKeyName,
SECURITY_INFORMATION secInfo,
PSECURITY_DESCRIPTOR pSD
)
{
HRESULT hr;
LPWSTR pszServerName = NULL;
LPWSTR pszKeyName = NULL;
LPWSTR pszSubKey = NULL;
DWORD dwErr;
HKEY hKey = NULL;
HKEY hKeyRoot = NULL;
HKEY hKeyMachine = NULL;
//
// We need to split the name into serverName and shareName
//
hr = GetServerAndResource(
pszFileRegKeyName,
&pszServerName,
&pszKeyName
);
BAIL_ON_FAILURE(hr);
//
// pszKeyName has to have a valid string. We need to process it
// to find out which key set we need to open (such as HKLM).
//
hr = GetKeyRootAndSubKey(pszKeyName, &pszSubKey, &hKeyRoot);
BAIL_ON_FAILURE(hr);
//
// Need to open the hKeyRoot on the appropriate machine.
// If the serverName is NULL it will be local machine.
//
dwErr = RegConnectRegistry(
pszServerName,
hKeyRoot,
&hKeyMachine
);
if (dwErr) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
//
// Open the key and try and read the security descriptor
//
dwErr = RegOpenKeyEx(
hKeyMachine,
pszSubKey,
0,
KEY_WRITE,
&hKey
);
if (dwErr) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
dwErr = RegSetKeySecurity(
hKey,
secInfo,
pSD
);
if (dwErr) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
error:
if (pszServerName) {
FreeADsStr(pszServerName);
}
if (pszKeyName) {
FreeADsStr(pszKeyName);
}
if (pszSubKey) {
FreeADsStr(pszSubKey);
}
if (hKey) {
RegCloseKey(hKey);
}
if (hKeyMachine) {
RegCloseKey(hKeyMachine);
}
RRETURN(hr);
}
/****************************************************************************/
//
// CADsSecurityUtility Class.
//
/****************************************************************************/
DEFINE_IDispatch_Implementation(CADsSecurityUtility)
//+---------------------------------------------------------------------------
// Function: CSecurity::CSecurityDescriptor - Constructor.
//
// Synopsis: Standard constructor.
//
// Arguments: N/A.
//
// Returns: N/A.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
CADsSecurityUtility::CADsSecurityUtility():
_secInfo( DACL_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
| OWNER_SECURITY_INFORMATION
),
_pDispMgr(NULL)
{
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::~CADsSecurityUtility - Destructor.
//
// Synopsis: Standard destructor.
//
// Arguments: N/A.
//
// Returns: N/A.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
CADsSecurityUtility::~CADsSecurityUtility()
{
//
// Only the dispmgr needs to be cleaned up.
//
delete _pDispMgr;
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::AllocateADsSecurityUtilityObject -
// Static helper method.
//
// Synopsis: Standard static allocation routine.
//
// Arguments: ppADsSecurityUtil - Return ptr.
//
// Returns: S_OK on success or appropriate error code on failure.
//
// Modifies: *ppADsSecurity.
//
//----------------------------------------------------------------------------
HRESULT
CADsSecurityUtility::AllocateADsSecurityUtilityObject(
CADsSecurityUtility **ppADsSecurityUtil
)
{
HRESULT hr = S_OK;
CADsSecurityUtility FAR * pADsSecurityUtil = NULL;
CDispatchMgr FAR * pDispMgr = NULL;
pADsSecurityUtil = new CADsSecurityUtility();
if (!pADsSecurityUtil) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pDispMgr = new CDispatchMgr;
if (!pDispMgr) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = LoadTypeInfoEntry(
pDispMgr,
LIBID_ADs,
IID_IADsSecurityUtility,
(IADsSecurityUtility *)pADsSecurityUtil,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
pADsSecurityUtil->_pDispMgr = pDispMgr;
*ppADsSecurityUtil = pADsSecurityUtil;
RRETURN(hr);
error:
delete pADsSecurityUtil;
delete pDispMgr;
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::CreateADsSecurityUtility - Static
// helper method.
//
// Synopsis: Standard static class factor helper method.
//
// Arguments: riid - IID needed on returned object.
// ppvObj - Return ptr.
//
// Returns: S_OK on success or appropriate error code on failure.
//
// Modifies: *ppvObj is suitably modified.
//
//----------------------------------------------------------------------------
HRESULT
CADsSecurityUtility::CreateADsSecurityUtility(
REFIID riid,
void **ppvObj
)
{
CADsSecurityUtility FAR * pADsSecurityUtil = NULL;
HRESULT hr = S_OK;
hr = AllocateADsSecurityUtilityObject(&pADsSecurityUtil);
BAIL_ON_FAILURE(hr);
hr = pADsSecurityUtil->QueryInterface(riid, ppvObj);
BAIL_ON_FAILURE(hr);
pADsSecurityUtil->Release();
RRETURN(hr);
error:
delete pADsSecurityUtil;
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::QueryInterface --- IUnknown support.
//
// Synopsis: Standard query interface method.
//
// Arguments: iid - Interface requested.
// ppInterface - Return pointer to interface requested.
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: *ppInterface to return interface pointer.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CADsSecurityUtility::QueryInterface(
REFIID iid,
LPVOID *ppInterface
)
{
HRESULT hr = S_OK;
if (!ppInterface) {
RRETURN(E_INVALIDARG);
}
if (IsEqualIID(iid, IID_IUnknown)) {
*ppInterface = (IADsSecurityUtility *) this;
}
else if (IsEqualIID(iid, IID_IDispatch)) {
*ppInterface = (IADsSecurityUtility *) this;
}
else if (IsEqualIID(iid, IID_IADsSecurityUtility)) {
*ppInterface = (IADsSecurityUtility *) this;
}
else if (IsEqualIID(iid, IID_ISupportErrorInfo)) {
*ppInterface = (ISupportErrorInfo *) this;
}
else {
RRETURN(E_NOINTERFACE);
}
AddRef();
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::InterfaceSupportserrorInfo
// ISupportErrorInfo support.
//
// Synopsis: N/A.
//
// Arguments: riid - Interface being tested..
//
// Returns: S_OK or S_FALSE on failure.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CADsSecurityUtility::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
{
if (IsEqualIID(riid, IID_IADsSecurityUtility)) {
return S_OK;
} else {
return S_FALSE;
}
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::GetSecurityDescriptor -
// IADsSecurityUtility support.
//
// Synopsis: Gets the security descriptor from the named object.
//
// Arguments: varPath - Path of object to get SD from.
// lPathFormat - Specifies type of object path.
// Only ADS_PATH_FILE, ADS_PATH_FILESHARE
// and ADS_PATH_REGISTRY are supported.
// lOutFormat - Specifies output SD format.
// pVariant - Return value for SD.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pVariant is update appropriately.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CADsSecurityUtility::GetSecurityDescriptor(
IN VARIANT varPath,
IN long lPathFormat,
IN OPTIONAL long lOutFormat,
OUT VARIANT *pVariant
)
{
HRESULT hr = S_OK;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
DWORD dwLength = 0;
VARIANT *pvPath = NULL;
//
// Make sure the params are correct.
//
if (!pVariant) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
VariantInit(pVariant);
if (lPathFormat < ADS_PATH_FILE
|| lPathFormat > ADS_PATH_REGISTRY
) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
//
// Make sure we handle byRef params correctly.
//
pvPath = &varPath;
if (V_VT(pvPath) == (VT_BYREF|VT_VARIANT)) {
pvPath = V_VARIANTREF(&varPath);
}
//
// For the path to be valid for now, it has to be a string.
//
if (pvPath->vt != VT_BSTR) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
if (pvPath->bstrVal == NULL) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
if (lOutFormat < ADS_SD_FORMAT_IID
|| lOutFormat > ADS_SD_FORMAT_HEXSTRING
) {
BAIL_ON_FAILURE(hr);
}
//
// Time to get the raw sd from the source.
//
switch (lPathFormat) {
case ADS_PATH_FILE:
hr = GetRawSDFromFile(
pvPath->bstrVal,
_secInfo,
&pSecurityDescriptor,
&dwLength
);
break;
case ADS_PATH_FILESHARE:
hr = GetRawSDFromFileShare(
pvPath->bstrVal,
&pSecurityDescriptor,
&dwLength
);
break;
case ADS_PATH_REGISTRY:
hr = GetRawSDFromRegistry(
pvPath->bstrVal,
_secInfo,
&pSecurityDescriptor,
&dwLength
);
break;
default:
hr = E_INVALIDARG;
break;
} // end of case to read sd.
BAIL_ON_FAILURE(hr);
//
// Now convert the sd to the required format.
//
switch (lOutFormat) {
case ADS_SD_FORMAT_IID:
hr = BinarySDToSecurityDescriptor(
pSecurityDescriptor,
pVariant,
NULL,
NULL,
NULL,
0
);
break;
case ADS_SD_FORMAT_RAW:
hr = ConvertRawSDToBinary(
pSecurityDescriptor,
dwLength,
pVariant
);
break;
case ADS_SD_FORMAT_HEXSTRING:
hr = ConvertRawSDToHexString(
pSecurityDescriptor,
dwLength,
pVariant
);
break;
default:
hr = E_INVALIDARG;
} // end of case for output format.
error:
if (pSecurityDescriptor) {
FreeADsMem(pSecurityDescriptor);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::SetSecurityDescriptor -
// IADsSecurityUtility support.
//
// Synopsis: Sets the security descriptor from the named object.
//
// Arguments: varPath - Path of object to set SD on.
// lPathFormat - Format of path.
// varData - Variant with SD to set.
// lDataFormat - Format of the SD data.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CADsSecurityUtility::SetSecurityDescriptor(
IN VARIANT varPath,
IN long lPathFormat,
IN VARIANT varData,
IN long lDataFormat
)
{
HRESULT hr = E_INVALIDARG;
VARIANT *pvPath = NULL;
VARIANT *pvData = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD dwLength = 0;
if ((lPathFormat < ADS_PATH_FILE)
|| (lPathFormat > ADS_PATH_REGISTRY)
|| (lDataFormat < ADS_SD_FORMAT_IID)
|| (lDataFormat > ADS_SD_FORMAT_HEXSTRING)
) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
//
// Make sure we handle byRef params correctly.
//
pvPath = &varPath;
if (V_VT(pvPath) == (VT_BYREF | VT_VARIANT)) {
pvPath = V_VARIANTREF(&varPath);
}
pvData = &varData;
if (V_VT(pvData) == (VT_BYREF | VT_VARIANT)) {
pvData = V_VARIANTREF(&varData);
}
//
// Find out what format the SD is in and convert to raw binary
// format as that is what we need to set.
//
switch (lDataFormat) {
case ADS_SD_FORMAT_IID:
hr = SecurityDescriptorToBinarySD(
*pvData,
&pSD,
&dwLength,
NULL,
NULL,
NULL,
0
);
break;
case ADS_SD_FORMAT_HEXSTRING:
if (V_VT(pvData) == VT_BSTR) {
hr = ConvertHexSDToRawSD(
pvData,
&pSD,
&dwLength
);
}
break;
case ADS_SD_FORMAT_RAW:
if (V_VT(pvData) == (VT_UI1 | VT_ARRAY)) {
hr = ConvertBinarySDToRawSD(
pvData,
&pSD,
&dwLength
);
}
default:
hr = E_INVALIDARG;
break;
} // end switch type of input data.
//
// This will catch conversion failures as well as bad params.
//
BAIL_ON_FAILURE(hr);
//
// For now the path has to be a string.
//
if (pvPath->vt != VT_BSTR) {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
switch (lPathFormat) {
case ADS_PATH_FILE:
hr = SetRawSDToFile(
pvPath->bstrVal,
_secInfo,
pSD
);
break;
case ADS_PATH_FILESHARE:
hr = SetRawSDToFileShare(
pvPath->bstrVal,
pSD
);
break;
case ADS_PATH_REGISTRY:
hr = SetRawSDToRegistry(
pvPath->bstrVal,
_secInfo,
pSD
);
break;
default:
hr = E_INVALIDARG;
break;
}
BAIL_ON_FAILURE(hr);
error:
if (pSD) {
FreeADsMem(pSD);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CADsSecurityUtility::ConvertSecurityDescriptor -
// IADsSecurityUtility method.
//
// Synopsis: Converts the input SD to the appropriate format requested.
//
// Arguments: varData - Input SD to convert.
// lDataFormat - Input SD format.
// loutFormat - Format of output SD.
// pvResult - Return value.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pvResult with appropriate value.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CADsSecurityUtility::ConvertSecurityDescriptor(
IN VARIANT varData,
IN long lDataFormat,
IN long lOutFormat,
OUT VARIANT *pvResult
)
{
HRESULT hr;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD dwLenSD;
VARIANT *pVarData = &varData;
if (!pvResult) {
BAIL_ON_FAILURE(hr= E_INVALIDARG);
}
if (V_VT(pVarData) == (VT_BYREF | VT_VARIANT)) {
pVarData = V_VARIANTREF(&varData);
}
//
// We will convert to binary format and then to
// the requested format.
//
switch (lDataFormat) {
case ADS_SD_FORMAT_IID:
hr = SecurityDescriptorToBinarySD(
*pVarData,
&pSD,
&dwLenSD,
NULL,
NULL,
NULL,
0
);
break;
case ADS_SD_FORMAT_RAW :
hr = ConvertBinarySDToRawSD(
pVarData,
&pSD,
&dwLenSD
);
break;
case ADS_SD_FORMAT_HEXSTRING:
hr = ConvertHexSDToRawSD(
pVarData,
&pSD,
&dwLenSD
);
break;
default:
hr = E_INVALIDARG;
break;
}
BAIL_ON_FAILURE(hr);
//
// Convert to the requested format.
//
switch (lOutFormat) {
case ADS_SD_FORMAT_IID:
hr = BinarySDToSecurityDescriptor(
pSD,
pvResult,
NULL,
NULL,
NULL,
0
);
break;
case ADS_SD_FORMAT_RAW:
hr = ConvertRawSDToBinary(
pSD,
dwLenSD,
pvResult
);
break;
case ADS_SD_FORMAT_HEXSTRING:
hr = ConvertRawSDToHexString(
pSD,
dwLenSD,
pvResult
);
break;
default:
hr = E_INVALIDARG;
break;
}
error:
if (pSD) {
FreeADsMem(pSD);
}
RRETURN(hr);
}
STDMETHODIMP
CADsSecurityUtility::put_SecurityMask(
long lSecurityMask
)
{
_secInfo = (SECURITY_INFORMATION) lSecurityMask;
RRETURN(S_OK);
}
STDMETHODIMP
CADsSecurityUtility::get_SecurityMask(
long *plSecurityMask
)
{
if (!plSecurityMask) {
RRETURN(E_INVALIDARG);
}
*plSecurityMask = (long) _secInfo;
RRETURN(S_OK);
}