Working with Group Policy Objects Programmatically

来源:互联网 发布:wit.ai api.ai 知乎 编辑:程序博客网 时间:2024/05/17 17:16
In my last bog post:
http://blogs.msdn.com/dsadsi/archive/2009/07/23/working-with-group-policy-objects-programmatically-determining-registry-values-to-enable-disable-set-a-specific-policy.aspx
I discussed an empirical method to determine the values one needs to write to the registry to enable/disable/set a registry based group policy.  In this post, I will provide a simple C++ function that illustrates how to write the key information into the GPO.
For now, lets concentrate on the C++ code for modifying the GPO.
The function requires 3 pieces of information:
ADsPath to the GPO object to modify
A mode control values, 0=Not Configured, 1=Enabled, 2=Disabled
The actual value to write in the key that represents the mode control value. 
The source for the function follows.  The comments should provide insight into how the code works.
One key point is to realize that if you are modifying an existing GPO that contains multiple settings on a specific registry key tree, you cannot just delete the entire key tree, you must delete just the values that affect the settings you are working with.
Another subtle gotcha is the way you use the IGroupPolicyObject::GetRegistryKey and the IGroupPolicyObject::Save methods.  The flag on in GetRegistryKey to indicate the section is an unsigned valued ( GPO_SECTION_ROOT or GPO_SECTION_USER or GPO_SECTION_MACHINE) , the flag to indicate the section on the Save method is a boolean ( TRUE to write the machine configuration, FALSE to write the user configuration).  I made the mistake of using the same value in both locations, and thought I was chasing a bug in the IGroupPolicyObject interface.
Finding the path can be a challenge.  The next blog post will provide details on how to locate a GPO object in the AD based on specific information using either the GPMC object model or the BrowseForGPO function.
C++ Source Code follows:
HRESULT ModifyUserPolicyForPreventAccessToCmdPrompt( BSTR bGPOPath, int iMode, DWORD lData)
{
    HRESULT hr=S_OK;
    //
    // Use IGroupPolicyObject to retrieve and modify the registry settings.
    // for the GPO represented by the gpoInfo.lpDsPath
    //
    IGroupPolicyObject* p = NULL;
    hr = CoCreateInstance(CLSID_GroupPolicyObject, NULL,
                          CLSCTX_INPROC_SERVER, IID_IGroupPolicyObject,
                          (LPVOID*)&p);
    if (SUCCEEDED(hr))
    {
        //
        // The GPO value we want to modify is the
        //
        // User Configuration
        //   +> Policies
        //        +>Administrative Templates
        //            +->System
        //                 +->Prevent access to the command prompt
        //
        DWORD dwSection = GPO_SECTION_USER;
        HKEY hGPOSectionKey = NULL;
        DWORD dwData;
        HKEY hSettingKey;
        LSTATUS rStatus;
        hr = 0;
        //
        //Open the GPO and load its registy values for both: Machine and user
        //
        hr = p->OpenDSGPO( bGPOPath, GPO_OPEN_LOAD_REGISTRY);
        //
        // Request the user Registy hive for the GPO
        //
        hr = p->GetRegistryKey(dwSection, &hGPOSectionKey);
        //
        // Determine if you want to set it to Not Congigure,
        //  Enabled or Disabled for the GPO itself.
        //
        // The second call, RequestSetting will provide the "Yes" or "No"
        // value for setting
        // the policy as shown by the GPO Editor
        //
        // iMode
        // 0=Not Configured, 1=Enabled, 2=Disabled
        //
        switch (iMode)
        {
        case 0:
            //
            // We do not want to configure the GPO, but we don't want to
            // affect other GPOs on the same key,
            // so just delete values associated with this
            // particular GPO setting.
            //
            rStatus = RegDeleteValue(hGPOSectionKey,
                L"Software\\Policies\\Microsoft\\Windows\\System\\DisableCMD"
                                     );
            rStatus = RegDeleteValue(hGPOSectionKey,
          L"Software\\Policies\\Microsoft\\Windows\\System\\**del.DisableCMD"
                                     );
            break;
        case 1:
            {
                //
                // To enable the policy, the DisableCMD value must
                // exist and the **del.DisableCMD value must not.
                //
                // lData:
                //
                // Check to see if the key for this policy exists. 
                // If if it does, retrieve a handle
                // If not, create it.
                //
                if( RegOpenKeyEx( hGPOSectionKey,
                        L"Software\\Policies\\Microsoft\\Windows\\System", 0,
                        KEY_WRITE, &hSettingKey) != ERROR_SUCCESS )
                {
                    rStatus = RegCreateKeyEx(
                        hGPOSectionKey,
                        L"Software\\Policies\\Microsoft\\Windows\\System",
                        0,
                        NULL,
                        REG_OPTION_NON_VOLATILE,
                        KEY_WRITE,
                        NULL,
                        &hSettingKey,
                        NULL );
                }
                //
                // Set the value DisableCMD and allow, disallow
                // script launching of CMD 
                //
                rStatus = RegSetValueEx(hSettingKey, L"DisableCMD",
                                        NULL, REG_DWORD, (BYTE *)(&lData),
                                        sizeof(DWORD));
                //
                // Remove the not configured value indicator from the hive.
                // It may not exist, so the RegDeleteValue may return
                // and error, this can be ignored.
                //
                rStatus = RegDeleteValue(hGPOSectionKey,
          L"Software\\Policies\\Microsoft\\Windows\\System\\**del.DisableCMD"
                                         );
                rStatus = RegCloseKey(hSettingKey);
                break;
            }
        case 2:
            {
                //
                // Disable the policy.
                // must remove the DisableCMD value and add the
                //  **del.DisableCMD value.
                //
                // Same stesp as before, check to see if the key for this
                // policy exists,
                // if not, create it.
                //
                BOOL bCreate = FALSE;
                if( RegOpenKeyEx( hGPOSectionKey, L"Software\\Policies\\Microsoft\\Windows\\System", 0, KEY_WRITE, &hSettingKey) != ERROR_SUCCESS )
                {
                    rStatus = RegCreateKeyEx(
                        hGPOSectionKey,
                        L"Software\\Policies\\Microsoft\\Windows\\System",
                        0,
                        NULL,
                        REG_OPTION_NON_VOLATILE,
                        KEY_WRITE,
                        NULL,
                        &hSettingKey,
                        NULL );
                    bCreate = TRUE;
                }
                DWORD dwType = 0;
                DWORD cbType = sizeof( dwData );
                if( !bCreate )
                {
                    //
                    // If we did not create the key, then our value
                    //  *may* exist.
                    // try to read it.  If we succeed, write that value back
                    //  to **del.DisableCMD
                    // if not, then set **del.DisableCMD to 0
                    //
                    rStatus = RegGetValue(hGPOSectionKey,
                                          L"Software\\Policies\\Microsoft\\Windows\\System", L"DisableCMD", RRF_RT_ANY, &dwType, (BYTE *)(&dwData), &cbType);
                    if( rStatus != ERROR_SUCCESS ) dwData = 0;
                    else RegDeleteValue( hSettingKey, L"DisableCMD");
                    rStatus = RegSetValueEx(hSettingKey, L"**del.DisableCMD", NULL, REG_DWORD, (BYTE *)(&dwData), sizeof(DWORD));
                }
                else
                {
                    //
                    // The key was created, just set the **del.DisableCMD
                    // value to 0
                    //
                    dwData = 0;
                    rStatus = RegSetValueEx(hSettingKey, L"**del.DisableCMD", NULL, REG_DWORD, (BYTE *)(&dwData), sizeof(DWORD));
                }
                rStatus = RegCloseKey(hSettingKey);
            }
        }
 
        GUID RegistryId = REGISTRY_EXTENSION_GUID;
        GUID ThisAdminToolGuid =
            /*{ CLSID_PolicySnapinUser/* */
        {
            0x0F6B957E,
            0x509E,
            0x11D1,
            {0xA7, 0xCC, 0x00, 0x00, 0xF8, 0x75, 0x71, 0xE3}
        };
        rStatus = RegCloseKey(hGPOSectionKey);
        //
        // Write the GPO back to the directory
        //
        hr = p->Save(
            FALSE,
            TRUE,
            &RegistryId,
            &ThisAdminToolGuid );
 
        hr = p->Release();
    }
    return hr;
}








获取组策略中的密码策略只用到了一个api函数 NetUserModalsGet, 具体用法去查MSDN。单靠这一个函数获取的内容还不全面,密码复杂性是否启用不能获取到,还需要再读一下注册表。读取HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account  键下的“F”键值--一段二进制数据,其中的第80(0开始)个字节为密码长度, 第76个字节为密码复杂性检查是否启用的标记。1代表启用,0代表未启用。 编译时选择uincode。
#include "stdafx.h"  
#include <stdio.h>  
#include <windows.h>   
#include <lm.h>  
#include <Aclapi.h>  
  
#pragma comment(lib,"Advapi32")  
#pragma  comment(lib, "Netapi32.lib")  
  
typedef  struct   
{  
    int  Complex;  //密码复杂性是否已启用  
    int  Len;      //密码最小长度  
}PwdComplex;  
  
bool  ModifyRegCompetence(LPSTR Group, LPSTR key);  
  
bool GetPwdComplex(PwdComplex* pCom);  
  
int wmain(int argc, wchar_t *argv[])  
{  
  
    DWORD dwLevel = 0;  
    USER_MODALS_INFO_0 *pBuf = NULL;  
    NET_API_STATUS nStatus;  
    LPTSTR pszServerName = NULL;  
  
    if (argc > 2)  
    {  
        fwprintf(stderr, L"Usage: %s [\\\\ServerName]\n", argv[0]);  
        exit(1);  
    }  
  
    if (argc == 2)  
        pszServerName = argv[1];  
      
    nStatus = NetUserModalsGet(pszServerName,  
        dwLevel,  
        (LPBYTE *)&pBuf);  
      
    if (nStatus == NERR_Success)  
    {  
        if (pBuf != NULL)  
        {  
            printf("\tMinimum password length:  %d\n", pBuf->usrmod0_min_passwd_len);  
            printf("\tMaximum password age (d): %d\n", pBuf->usrmod0_max_passwd_age/86400);  
            printf("\tMinimum password age (d): %d\n", pBuf->usrmod0_min_passwd_age/86400);  
            printf("\tForced log off time (s):  %d\n", pBuf->usrmod0_force_logoff);  
            printf("\tPassword history length:  %d\n", pBuf->usrmod0_password_hist_len);  
        }  
    }  
      
    else  
        fprintf(stderr, "A system error has occurred: %d\n", nStatus);  
      
    if (pBuf != NULL)  
        NetApiBufferFree(pBuf);  
  
    //修改权限对Administrators开放  
    bool bModify = ModifyRegCompetence("Administrators", "MACHINE\\SAM\\SAM");  
  
    PwdComplex complex;  
    if(GetPwdComplex(&complex))  
    {  
        printf("\tPassword Complexity :  %s\n", (complex.Complex ?  "密码复杂性已使用":"密码复杂性已禁用"));  
        printf("\tPassword len :  %d\n", complex.Len);  
    }  
  
    return 0;  
}  
  
bool  ModifyRegCompetence(LPSTR Group, LPSTR key)  
{  
    PACL pOldDacl=NULL;  
    PACL pNewDacl=NULL;  
    DWORD dRet;  
    EXPLICIT_ACCESS_A eia;  
    PSECURITY_DESCRIPTOR pSID=NULL;  
    dRet = GetNamedSecurityInfoA(key,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,&pOldDacl,NULL,&pSID);// 获取SAM主键的DACL   
    if(dRet != ERROR_SUCCESS)  
        goto END;  
    //创建一个ACE,允许Administrators组成员完全控制对象,并允许子对象继承此权限  
    ZeroMemory(&eia,sizeof(EXPLICIT_ACCESS_A));  
    BuildExplicitAccessWithNameA(&eia,Group, KEY_ALL_ACCESS,SET_ACCESS,SUB_CONTAINERS_AND_OBJECTS_INHERIT);  
    // 将新的ACE加入DACL   
    dRet = SetEntriesInAclA(1,&eia,pOldDacl,&pNewDacl);  
    if(dRet != ERROR_SUCCESS)  
        goto END;  
    // 更新SAM主键的DACL   
    dRet = SetNamedSecurityInfoA(key,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL);  
    if(dRet != ERROR_SUCCESS)  
        goto END;  
END:      
        //释放DACL和SID  
    if(pNewDacl)  
        LocalFree(pNewDacl);  
    if(pSID)  
        LocalFree(pSID);  
    return 1;  
}  
  
bool GetPwdComplex(PwdComplex* pCom)  
{  
    HKEY hKey;  
    long lResult;  
    char buf[MAX_PATH] = {0};  
    DWORD len = MAX_PATH;  
    lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SAM\\SAM\\Domains\\Account"),  
        0, KEY_READ, &hKey);  
    if(lResult != ERROR_SUCCESS)  
        return 0;  
    lResult = ::RegQueryValueEx(hKey, _T("F"), NULL, NULL, (LPBYTE)buf, &len);  
    if(lResult != ERROR_SUCCESS)  
        return 0;  
    RegCloseKey(hKey);  
  
    pCom->Complex =(int)buf[76];  
    pCom->Len  = (int)buf[80];  
    return 1;  
}  
修改组策略需要注意 IGroupPolicyObject
使用IGroupPolicyObject修改组策略后,
1、要记得调用save。
    GUID guid1 = REGISTRY_EXTENSION_GUID;
    hr = p->Save(
        TRUE,
        TRUE,
        const_cast<GUID*>(&guid1),
        const_cast<GUID*>(&CLSID_GPESnapIn)
        );




2、如果要查看自己的修改是否起作用了,一定要 关闭当前打开的mmc.exe,重新运行gpedit.msc。 


3、
组策略的生效一般会90分钟左右
要立即生效,调用api :
 bRes = RefreshPolicy(TRUE);


就可以了。
0 0
原创粉丝点击