How to correctly change DCOM permissions in registry using c++?

Stanislav Panferov 50 Баллы репутации
2024-12-30T07:02:00.37+00:00

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.

Windows
Windows
Семейство операционных систем Майкрософт, работающих на персональных компьютерах, планшетах, ноутбуках, телефонах, устройствах Интернета вещей, автономных гарнитурах смешанной реальности, больших экранах совместной работы и других устройствах.
Вопросы: 24
C++
C++
Высокоуровневый язык программирования общего назначения, созданный как расширение языка программирования C, который имеет объектно-ориентированные, универсальные и функциональные функции в дополнение к средствам для низкоуровневой обработки памяти.
Вопросы: 4
Комментариев: 0 Без комментариев
Голосов: {count}

Ваш ответ

Автор вопроса может помечать ответы как принятые. Это позволяет пользователям узнать, что ответ помог решить проблему автора.