How to correctly change DCOM permissions in registry using c++?
I am trying to modify DCOM permissions in my native C++ project, which is COM Server. Following the documentation (1) and documentation (2) as well as this post, I create new absolute security descriptors from EXPLICIT_ACCESS for AccessPermission and LaunchPermission as described here. Then I convert absolute security descriptors to self-relative using MakeSelfRelativeSD. Resulting self-relative security descriptors I cast to BYTE* and write them to the appropriate registry keys using RegSetValue. But when I then view the DCOM permissions using DCOM Confing, they don't match the programmatically set values. What is wrong?
enum COM_RIGHTS : DWORD
{
COM_NONE = 0,
COM_EXECUTE = 1,
COM_EXECUTE_LOCAL = 2,
COM_EXECUTE_REMOTE = 4,
COM_ACTIVATE_LOCAL = 8,
COM_ACTIVATE_REMOTE = 16
};
template<typename T>
class ACCOUNT_INFORMATION
{
public:
basic_string<T> strAccountName;
basic_string<T> strDomainName;
PSID pSid;
DWORD dwSidLength;
SID_NAME_USE sidNameUse;
DWORD accessRights;
ACCOUNT_INFORMATION(
basic_string<T> strNewAccountName = basic_string<T>(),
basic_string<T> strNewDomainName = basic_string<T>(),
PSID pNewSid = NULL,
SID_NAME_USE newSidNameUse = SID_NAME_USE::SidTypeUnknown,
COM_RIGHTS newAccessRights = COM_RIGHTS::COM_NONE);
};
template<typename T>
using PACCOUNT_INFORMATION = ACCOUNT_INFORMATION<T>*;
vector<PSID> SecurityHelper::LocalGroupsSid = SecurityHelper::GetLocalGroupsSid();
template<size_t N>
BOOL SecurityHelper::SetDComPermissionsForAccounts(
RegistryKey* pregKeyAppId,
const LPCSTR (&rgszAccountNames)[N],
const COM_RIGHTS (&rgAccessRights)[N],
const COM_RIGHTS (&rgLaunchRights)[N])
{
return SetDComPermissions(pregKeyAppId, rgszAccountNames, rgAccessRights, rgszAccountNames, rgAccessRights);
}
template<size_t N>
BOOL SecurityHelper::SetDComPermissions(
HKEY hKeyAppId,
const LPCSTR (&rgszAccessForAccountNames)[N],
const COM_RIGHTS (&rgAccessRights)[N],
const LPCSTR (&rgszLaunchAsAccountNames)[N],
const COM_RIGHTS (&rgLaunchRights)[N])
{
BOOL fIsPermissionsSet = FALSE;
if(hKeyAppId != NULL)
{
size_t size1 = 0, size2 = 0;
LPCSTR* lpcszAccessForAccountNames = (LPCSTR*)&rgszAccessForAccountNames;
LPCSTR* lpcszLaunchForAccountNames = (LPCSTR*)&rgszLaunchAsAccountNames;
DWORD* pAccessRights = (DWORD*)(COM_RIGHTS*)&rgAccessRights;
DWORD* pLaunchRights = (DWORD*)(COM_RIGHTS*)&rgLaunchRights;
vector<LPCSTR> vectorAccessForAccountNames(lpcszAccessForAccountNames, lpcszAccessForAccountNames + N);
vector<LPCSTR> vectorLaunchAsAccountNames(lpcszLaunchForAccountNames, lpcszLaunchForAccountNames + N);
vector<DWORD> vectorAccessRights(pAccessRights, pAccessRights + N);
vector<DWORD> vectorLaunchRights(pLaunchRights, pLaunchRights + N);
pair<BOOL, PSECURITY_DESCRIPTOR> pairSDAccessPermissions =
CreateSecurityDescriptor(vectorAccessForAccountNames, vectorAccessRights);
pair<BOOL, PSECURITY_DESCRIPTOR> pairSDLaunchPermissions =
CreateSecurityDescriptor(vectorLaunchAsAccountNames, vectorLaunchRights);
if(pairSDAccessPermissions.first && pairSDLaunchPermissions.first)
{
DWORD dwSDAccessPermissionsLength = 0;
DWORD dwSDLaunchPermissionsLength = 0;
if(!MakeSelfRelativeSD(pairSDAccessPermissions.second, NULL, &dwSDAccessPermissionsLength) && GetLastError() == ERROR_INSUFFICIENT_BUFFER
&& dwSDAccessPermissionsLength > 0
&& !MakeSelfRelativeSD(pairSDLaunchPermissions.second, NULL, &dwSDLaunchPermissionsLength) && GetLastError() == ERROR_INSUFFICIENT_BUFFER
&& dwSDLaunchPermissionsLength > 0)
{
PSECURITY_DESCRIPTOR pSDAccessPermissions = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDAccessPermissionsLength);
PSECURITY_DESCRIPTOR pSDLaunchPermissions = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDLaunchPermissionsLength);
if(MakeSelfRelativeSD(pairSDAccessPermissions.second, pSDAccessPermissions, &dwSDAccessPermissionsLength) && pSDAccessPermissions != NULL
&& MakeSelfRelativeSD(pairSDLaunchPermissions.second, pSDLaunchPermissions, &dwSDLaunchPermissionsLength) && pSDLaunchPermissions != NULL)
{
PBYTE bpSDAccessPermissions = (PBYTE)pSDAccessPermissions;
PBYTE bpSDLaunchPermissions = (PBYTE)pSDLaunchPermissions;
fIsPermissionsSet = RegSetKeyValue(hKeyAppId, NULL, L"AccessPermission", REG_BINARY, (LPCVOID)bpSDAccessPermissions, dwSDAccessPermissionsLength) == ERROR_SUCCESS
&& RegSetKeyValue(hKeyAppId, NULL, L"LaunchPermission", REG_BINARY, (LPCVOID)bpSDLaunchPermissions, dwSDLaunchPermissionsLength) == ERROR_SUCCESS
}
LocalFree(pSDAccessPermissions);
LocalFree(pSDLaunchPermissions);
}
}
}
return fIsPermissionsSet;
}
PSECURITY_DESCRIPTOR SecurityHelper::CreateSecurityDescriptor(vector<LPCSTR> vectorAccountNames, vector<DWORD> vectorAccessRights)
{
return CreateSecurityDescriptor(GetMapAccountInfo(vectorAccountNames, vectorAccessRights));
}
PSECURITY_DESCRIPTOR SecurityHelper::CreateSecurityDescriptor(map<PSID, ACCOUNT_INFORMATION<CHAR>> mapAccountInfo)
{
PSECURITY_DESCRIPTOR psd = NULL;
BOOL fIsCreated = FALSE;
vector<EXPLICIT_ACCESS> vectorExplicitAccess;
EXPLICIT_ACCESS ea;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
PEXPLICIT_ACCESS pExplicitAccess;
for(const pair<PSID, ACCOUNT_INFORMATION<CHAR>> curPair : mapAccountInfo)
{
pExplicitAccess = new EXPLICIT_ACCESS(ea);
switch(curPair.second.sidNameUse)
{
case SID_NAME_USE::SidTypeDomain:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_DOMAIN;
break;
case SID_NAME_USE::SidTypeComputer:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_COMPUTER;
break;
case SID_NAME_USE::SidTypeWellKnownGroup:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
break;
case SID_NAME_USE::SidTypeGroup:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_GROUP;
break;
case SID_NAME_USE::SidTypeUser:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_USER;
break;
case SID_NAME_USE::SidTypeLogonSession:
break;
case SID_NAME_USE::SidTypeAlias:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_ALIAS;
break;
case SID_NAME_USE::SidTypeLabel:
break;
case SID_NAME_USE::SidTypeInvalid:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_INVALID;
break;
case SID_NAME_USE::SidTypeUnknown:
pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
break;
}
pExplicitAccess->Trustee.ptstrName = (LPTSTR)curPair.second.pSid;
pExplicitAccess->grfAccessPermissions = curPair.second.accessRights;
vectorExplicitAccess.push_back(*pExplicitAccess);
}
DWORD dwEntriesCount = vectorExplicitAccess.size();
if(dwEntriesCount == mapAccountInfo.size())
{
PACL pDacl = NULL;
PEXPLICIT_ACCESS pExplicitAccess = new EXPLICIT_ACCESS[dwEntriesCount];
size_t size = dwEntriesCount * sizeof(EXPLICIT_ACCESS);
memset(pExplicitAccess, 0, size);
memcpy(pExplicitAccess, vectorExplicitAccess.data(), size);
if(SetEntriesInAcl(dwEntriesCount, pExplicitAccess, NULL, &pDacl) == ERROR_SUCCESS && pDacl != NULL)
{
psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(psd != NULL)
{
if(InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION))
{
BOOL fDaclPresent = TRUE;
BOOL fDaclDefaulted = FALSE;
fIsCreated = SetSecurityDescriptorDacl(psd, fDaclPresent, pDacl, fDaclDefaulted);
}
if(!fIsCreated)
{
LocalFree(psd);
}
}
}
}
return fIsCreated ? psd : NULL;
}
map<PSID, ACCOUNT_INFORMATION<CHAR>> SecurityHelper::GetMapAccountInfo(vector<LPCSTR> vectorAccountNames, vector<DWORD> vectorAccessRights)
{
map<PSID, ACCOUNT_INFORMATION<CHAR>> mapAccountInfo;
if(vectorAccountNames.size() > 0 && vectorAccessRights.size() == vectorAccountNames.size())
{
PACCOUNT_INFORMATION<CHAR> pAccountInfo = NULL;
for(int index = 0; index < vectorAccountNames.size(); index++)
{
pAccountInfo = SecurityHelper::GetAccountInformationFromNameA(vectorAccountNames[index]);
if(pAccountInfo != NULL && IsValidSid(pAccountInfo->pSid))
{
pAccountInfo->accessRights = vectorAccessRights[index];
mapAccountInfo[pAccountInfo->pSid] = *pAccountInfo;
}
}
}
return mapAccountInfo;
}
vector<PSID> SecurityHelper::GetLocalGroupsSid()
{
vector<PSID> vectorLocalGroupsSid;
PLOCALGROUP_INFO_0 pTmpGroupInfo = NULL;
DWORD entriesRead = 0;
DWORD totalEntries = 0;
NET_API_STATUS status = NetLocalGroupEnum(NULL, 0, (LPBYTE*)&pTmpGroupInfo, MAX_PREFERRED_LENGTH, (LPDWORD)&entriesRead, (LPDWORD)&totalEntries, (PDWORD_PTR)NULL);
if(status == NERR_Success && pTmpGroupInfo != NULL && entriesRead == totalEntries)
{
PLOCALGROUP_INFO_0 pGroupInfo = new LOCALGROUP_INFO_0[entriesRead + 1];
memset(pGroupInfo, 0, (entriesRead + 1) * sizeof(LOCALGROUP_INFO_0));
memcpy(pGroupInfo, pTmpGroupInfo, entriesRead * sizeof(LOCALGROUP_INFO_0));
LPCWSTR lpcwszInteractive = L"ИНТЕРАКТИВНЫЕ";
size_t dstSize = wcslen(lpcwszInteractive) + 1;
entriesRead++;
pGroupInfo[entriesRead-1].lgrpi0_name = new WCHAR[dstSize];
wcscpy_s(pGroupInfo[entriesRead-1].lgrpi0_name, dstSize, lpcwszInteractive);
LPWSTR lpwszAccountName = NULL;
PSID psidCurrent = NULL;
DWORD dwSidLength = 0;
LPWSTR lpwszSidCurrent = NULL;
LPWSTR lpwszDomainName = NULL;
DWORD dwDomainNameSize = 0;
SID_NAME_USE sidNameUse;
for(int index = 0; index < entriesRead; index++)
{
if(pGroupInfo[index].lgrpi0_name != NULL)
{
lpwszAccountName = const_cast<LPWSTR>(pGroupInfo[index].lgrpi0_name);
psidCurrent = NULL;
dwSidLength = 0;
lpwszDomainName = NULL;
dwDomainNameSize = 0;
if(!LookupAccountNameW(NULL, lpwszAccountName, NULL, &dwSidLength, NULL, &dwDomainNameSize, &sidNameUse)
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER && dwSidLength > 0 && dwDomainNameSize > 0)
{
psidCurrent = (PSID)new BYTE[dwSidLength];
lpwszDomainName = new WCHAR[dwDomainNameSize];
if(LookupAccountNameW(NULL, lpwszAccountName, psidCurrent, &dwSidLength, lpwszDomainName, &dwDomainNameSize, &sidNameUse))
{
lpwszSidCurrent = NULL;
ConvertSidToStringSidW(psidCurrent, &lpwszSidCurrent);
vectorLocalGroupsSid.push_back(psidCurrent);
LocalGroupNamesW.push_back(format(L"{}\\{}", lpwszDomainName, lpwszAccountName));
LocalGroupNamesA.push_back(format("{}\\{}", StringHelper::UnicodeToAnsi(lpwszDomainName), StringHelper::UnicodeToAnsi(lpwszAccountName)));
}
}
}
}
}
return vectorLocalGroupsSid;
}
PACCOUNT_INFORMATION<CHAR> SecurityHelper::GetAccountInformationFromNameA(LPCSTR lpcszAccountName)
{
PACCOUNT_INFORMATION<CHAR> pAccountInformation = NULL;
BOOL fResult = FALSE;
if(!StringHelper::IsEmptyStringA(lpcszAccountName))
{
pAccountInformation = new ACCOUNT_INFORMATION<CHAR>(string(lpcszAccountName));
DWORD dwDomainNameSize = 0;
LPSTR lpszDomainName = NULL;
fResult = LookupAccountNameA(
NULL,
lpcszAccountName,
pAccountInformation->pSid,
&pAccountInformation->dwSidLength,
lpszDomainName,
&dwDomainNameSize,
&pAccountInformation->sidNameUse);
if(!fResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER && pAccountInformation->dwSidLength > 0 && dwDomainNameSize > 0)
{
pAccountInformation->pSid = new BYTE[pAccountInformation->dwSidLength];
lpszDomainName = new CHAR[dwDomainNameSize];
fResult = LookupAccountNameA(
NULL,
lpcszAccountName,
pAccountInformation->pSid,
&pAccountInformation->dwSidLength,
lpszDomainName,
&dwDomainNameSize,
&pAccountInformation->sidNameUse);
if(fResult)
{
if(pAccountInformation->sidNameUse == SidTypeAlias
&& find_if(LocalGroupsSid.begin(), LocalGroupsSid.end(),
[&](PSID psidCurrent) -> bool { return EqualSid(psidCurrent, pAccountInformation->pSid); } ) != LocalGroupsSid.end())
{
pAccountInformation->sidNameUse = SidTypeWellKnownGroup;
}
if(lpszDomainName != NULL && dwDomainNameSize > 0)
{
pAccountInformation->strDomainName = string(lpszDomainName, dwDomainNameSize);
}
}
}
}
return fResult ? pAccountInformation : NULL;
}
COM_RIGHTS localAccessRights = (COM_RIGHTS)(COM_RIGHTS::COM_EXECUTE | COM_RIGHTS::COM_EXECUTE_LOCAL);
COM_RIGHTS localLaunchRights = (COM_RIGHTS)(COM_RIGHTS::COM_EXECUTE | COM_RIGHTS::COM_EXECUTE_LOCAL | COM_RIGHTS::COM_ACTIVATE_LOCAL);
COM_RIGHTS fullAccessRights = (COM_RIGHTS)(COM_RIGHTS::COM_EXECUTE | COM_RIGHTS::COM_EXECUTE_LOCAL | COM_RIGHTS::COM_EXECUTE_REMOTE);
COM_RIGHTS fullLaunchRights = (COM_RIGHTS)(COM_RIGHTS::COM_EXECUTE | COM_RIGHTS::COM_EXECUTE_LOCAL | COM_RIGHTS::COM_EXECUTE_REMOTE
| COM_RIGHTS::COM_ACTIVATE_LOCAL | COM_RIGHTS::COM_ACTIVATE_REMOTE);
SecurityHelper::SetDComPermissionsForAccounts(
pregKeyAppId,
{ "Пользователи", "ИНТЕРАКТИВНЫЕ", "СИСТЕМА", "Администраторы" },
{ localAccessRights, localAccessRights, fullAccessRights, fullAccessRights },
{ localLaunchRights, localLaunchRights, fullLaunchRights, fullLaunchRights }
);
I found solution. See my post on StackOverflow.