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 для ИТ-специалистов | Взаимодействие с пользователем | Прочее
Технологии для разработчиков | C++
Технологии для разработчиков | C++

Высокоуровневый, универсальный язык программирования, созданный как расширение языка программирования C, обладающий объектно-ориентированными, универсальными и функциональными функциями, а также возможностями для низкоуровневой работы с памятью.

Комментариев: 0 Без комментариев

Ваш ответ

Автор вопроса может устанавливать для ответов пометку "Принято", а модераторы — пометку "Рекомендуется". Благодаря этому пользователям становится проще понять, какой из ответов помог решить проблему автора.