Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Локальные политики пароля внутри домена


Автор: racner 28.6.2010, 19:48
Здравствуйте! =)

Может кто-нибудь знает, или имеет предположение, как на Visual C++ узнать локальные политики пароля?

Средствами Windows можно увидеть данные политики, если запустить: C:\Windows\System32\gpedit.msc.
Там во вкладке Computer Configuration -> Windows Settings -> Security Settings -> Account Policies -> Password Policy
можно увидеть интересующие меня значения, такие как maximum password length, Enforce password history и т.п.

Но как узнать данные значения средствами Visual C++, подскажите, пожалуйста, хотя бы в каком направлении рыть инфу )

Автор: jonie 29.6.2010, 07:47
racner, читай эту KB http://support.microsoft.com/kb/555540

Автор: racner 30.6.2010, 10:50
Цитата

racner, читай эту KB http://support.microsoft.com/kb/555540

Спасибо за ссылку. =) К сожалению, это не совсем то, что мне нужно. Возможно с помощью этих ключей в реестре можно создать какие-то дополнительные политики паролей в локальной системе. Но у меня задача стоит другая: узнать политики пароля в домене. 

Для моего решения подошла функция:

NetValidatePasswordPolicyFree

Вот привожу рабочий пример тестовой программки, которуюю сделал у себя:

Код

// test_30_06.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>
#include <Lm.h>
#include <iostream>
#include <windows.h>
#include <atlstr.h>
#include <conio.h>

#pragma comment( lib,"Netapi32.lib") 
#pragma comment( lib,"Mpr.lib") 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    CString strMachine_Name, strPassword, strOutInfo;

        char ch[250];
        wchar_t wch[250];

        cout << endl <<"Input computer name: \\\\";
        cin >>  ch;
        mbstowcs(wch,ch,250);
        strMachine_Name = wch;

        cout << endl <<"Input password for check: ";
        cin >> ch;
        mbstowcs(wch,ch,250);
        strPassword = wch;

    strMachine_Name = L"\\\\" + strMachine_Name;


      NET_API_STATUS stat; 

      NET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG InputArg = {0}; 

      NET_VALIDATE_OUTPUT_ARG* pOutputArg = NULL; 

      wchar_t* wzServer = strMachine_Name.GetBuffer(); 

      wchar_t* wzPwd = strPassword.GetBuffer(); 


      InputArg.ClearPassword = wzPwd; 

      InputArg.PasswordMatch = TRUE; 
       
      stat = NetValidatePasswordPolicy(wzServer, NULL, NetValidatePasswordChange, &InputArg, (void**)&pOutputArg); 

      switch(pOutputArg->ValidationStatus)
      {
            case NERR_AccountLockedOut : strOutInfo = "Validation failed. The account is locked out."; break;
            case NERR_PasswordTooRecent: strOutInfo = "Validation failed. The password for the user is too recent to change."; break;
            case NERR_BadPassword      : strOutInfo = "Validation failed. The password is invalid."; break;
            case NERR_PasswordHistConflict  : strOutInfo = "Validation failed. The password cannot be used at this time."; break;
            case NERR_PasswordTooShort : strOutInfo = "Validation failed. The password does not meet policy requirements because it is too short."; break;
            case NERR_PasswordTooLong  : strOutInfo = "Validation failed. The password does not meet policy requirements because it is too long."; break;
            case NERR_PasswordNotComplexEnough  : strOutInfo = "Validation failed. The password does not meet policy requirements because it is not complex enough."; break;
            case NERR_PasswordFilterError  : strOutInfo = "Validation failed. The password does not meet the requirements of the password filter DLL."; break;
            case NERR_Success : strOutInfo = "The password passes the validation check."; break;
      }

      wcscpy(wch,strOutInfo.GetBuffer());
      wcstombs(ch,wch,250);

      cout <<endl << endl << ch << endl << endl;

      getch();

      NetValidatePasswordPolicyFree((void**)&pOutputArg); 
}


В системе, в которой я её компилирую она работает хорошо (windows7). Ввожу имя контроллера домена и пароль, програма отвечает все как надо. 

Однако, если эту программку запусить на другой системе (windows XP) возникает ошибка: The procedure entry point NetValidatePasswordPolicy coluld not be localed in the dynamic link library NETAPI32.dll. В самой системе есть данная библиотека, но более ранней версии. Тупо заменить старый файл NetApi32.dll - нельзя, система не позволяет. 

Подскажите пожалуйста, как с этим бороться?

Автор: 12usver12 30.6.2010, 14:55
делай на XP проверку наличия в экспорте данной функции 
Код

GetProceAdress(hNetapi,"NetValidatePasswordPolicy ")

если отсуствует то носи с собой либу с екзешником и динамически бери оттуда

Автор: xvr 30.6.2010, 18:13
Цитата(12usver12 @  30.6.2010,  14:55 Найти цитируемый пост)
если отсуствует то носи с собой либу с екзешником
У меня есть ну очень БОЛЬШОЕ сомнение, что системная либа от Win7 заработает на WinXP  smile 
NB. В MSDN вообще написано, что НЕ для серверов она (NetValidatePasswordPolicy) не поддерживается

Автор: racner 3.7.2010, 18:01
Да, действительно, NetValidatePasswordPolicy не работает в Windows XP, т.к. библиотека WINAPI32.dll не экспортирует данную функцию, в отличие от более поздних версий dll-ки.

Зато нужные мне сведения показывает системная команда net accounts.

Но как получить политики паролей программным путем?

К счастью, мне удалось это сделать. Вот мой код на Visual Basic:
(кто хочет проверить, достаточно скопировать в текстовый файл с расширением *.vbs и запустить)
Код

Dim ns, temp, sCompName

sCompName = inputBox("Please input your computer name: ")
Set ns = GetObject("winmgmts://"&sCompName&"/root/rsop/computer")

Set colItems = ns.ExecQuery("Select * from RSOP_SecuritySettingBoolean")

For Each objItem in colItems
    temp = temp + "Category: " & objItem.KeyName + vbTab + vbTab
    temp = temp + "Settings: " & objItem.Setting
    temp = temp + vbCrLf
Next

Set colItems = ns.ExecQuery("Select * from RSOP_SecuritySettingNumeric")

For Each objItem in colItems
    temp = temp + "Category: " & objItem.KeyName + vbTab + vbTab
    temp = temp + "Settings: " & objItem.Setting
    temp = temp + vbCrLf
Next

msgbox temp


Однако возникли пробемы при попытке перевести данный код на С++. Аналог функции в GetObject в плюсах : ADsGetObject.

Может кто-то знает как перевести данный код на плюсы? =)

Вот моя заготовочка: 
Код

// test_07_02_2010_cmd.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "atlstr.h"
#include <iostream>
#include "windows.h"

#include "Iads.h"
#include "Adshlp.h"
                     
#pragma comment(lib,"Activeds.lib")
#pragma comment(lib,"NetApi32.lib")

using namespace std;

const IID IID_IADs = {0xFD8256D0, 0xFD15, 0x11CE, {0xAB,0xC4,0x02,0x60,0x8C,0x9E,0x75,0x53}};
const IID IID_IADsContainer = {0xFD8256D0, 0xFD15, 0x11CE, {0xAB,0xC4,0x02,0x60,0x8C,0x9E,0x75,0x53}}; 


int _tmain(int argc, _TCHAR* argv[])
{
        CString sCompName = getenv("COMPUTERNAME");
        CString sPath = L"winmgmts://"+sCompName+L"/root/rsop/computer";
        HRESULT hr;
        IADs *padsComp;
        IADs *padsRoot2;

        cout << endl << "sPath = " <<sPath.GetBuffer() << endl << endl << endl;
        hr = ADsGetObject((LPCWSTR)sPath.GetBuffer(), IID_IADs, (LPVOID*)&padsComp);

        /*    здесь должно быть продолжение     */

        return 0;
}

Автор: xvr 3.7.2010, 19:27
Цитата(racner @  3.7.2010,  18:01 Найти цитируемый пост)
Вот мой код на Visual Basic:
Это WMI. Смотрите в MSDN - там есть примеры как с ним работать из С++


Автор: racner 4.7.2010, 21:36
Всем спасибо за помощь.
Я решил для себя данный вопрос.

Составил вот такую вот программку, авось кому-нибудь пригодится =) :

Код

// test_07_02_2010_cmd.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "atlstr.h"
#include <iostream>
#include "windows.h"
#include "Wbemidl.h"

#pragma comment(lib,"Wbemuuid.lib")

using namespace std;

struct Struct_PolicyPassword
{
    int MaximumPasswordAge;
    int MinimumPasswordAge;
    int LockoutBadCount;
    int PasswordHistorySize;
    int MinimumPasswordLength;
    bool PasswordComplexity;
    bool ClearTextPassword;
    bool ForceLogoffWhenHourExpire;
    bool RequireLogonToChangePassword;
};


CString ErrorMessage(HRESULT hr, CString str="")
{
    CString sOutStr;
    void* pMsgBuf ;
 
    ::FormatMessage( 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        hr,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR)&pMsgBuf,
        0,
        NULL ) ;
    sOutStr.Format(L"[%s] Error (%x): %s", str.GetBuffer(), hr, (char*)pMsgBuf);
    LocalFree(pMsgBuf) ;

    return sOutStr;
}

CString GetWMIInformation(Struct_PolicyPassword &spp)
{
    HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
    if(hr) return ErrorMessage(hr,L"CoInitializeEx");

    CComPtr<IWbemLocator> w;
    hr = CoCreateInstance ( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**)&w);
    if(hr) return ErrorMessage(hr,L"CoCreateInstance");

    CString strAddr;
    strAddr.Format ( _T("\\\\%s\\root\\rsop\\computer"), CString(getenv("COMPUTERNAME")));
    CComPtr<IWbemServices> s;
    
    hr = w->ConnectServer(
        CComBSTR(strAddr),
        NULL,
        NULL,
        NULL,
        0, 
        NULL,
        NULL,
        &s );

    if(hr) return ErrorMessage(hr,L"ConnectServer");

    CComPtr<IEnumWbemClassObject> e;

    hr = s->ExecQuery(CComBSTR("WQL"),
        CComBSTR("Select * from RSOP_SecuritySettingNumeric"),
        WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
        NULL,
        &e);
    if(hr) return ErrorMessage(hr,L"ExecQuery");

    while(1)
    {
                CComPtr<IWbemClassObject> co;
                DWORD ret=0;

                hr = e->Next ( /*WBEM_NO_WAIT*/5000,
                              1,
                              &co,
                            &ret ); 
                if(hr) break;

                CComVariant v1,v2;
                CIMTYPE tp;

                hr = co->Get( L"KeyName",
                     0,
                     &v1,
                     &tp,
                     0 );
                if(hr) return ErrorMessage(hr,L"Get KeyName");

                hr = co->Get( L"Setting",
                     0,
                     &v2,
                     &tp,
                     0 );
                if(hr) return ErrorMessage(hr,L"Get Setting");

                if(!wcscmp(L"MaximumPasswordAge",v1.bstrVal)) { spp.MaximumPasswordAge=v2.intVal; continue; }
                if(!wcscmp(L"MinimumPasswordAge",v1.bstrVal)) { spp.MinimumPasswordAge=v2.intVal;  continue; }
                if(!wcscmp(L"LockoutBadCount",v1.bstrVal)) { spp.LockoutBadCount=v2.intVal; continue; }
                if(!wcscmp(L"PasswordHistorySize",v1.bstrVal)) { spp.PasswordHistorySize=v2.intVal; continue; }
                if(!wcscmp(L"MinimumPasswordLength",v1.bstrVal)) { spp.MinimumPasswordLength=v2.intVal; continue; }
    }

    CComPtr<IEnumWbemClassObject> e2;

    hr = s->ExecQuery(CComBSTR("WQL"),
        CComBSTR("Select * from RSOP_SecuritySettingBoolean"),
        WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
        NULL,
        &e2);

    while(1)
    {
                CComPtr<IWbemClassObject> co;
                DWORD ret=0;

                hr = e2->Next ( /*WBEM_NO_WAIT*/5000,
                              1,
                              &co,
                            &ret ); 
                if(hr) break;

                CComVariant v1,v2;

                hr = co->Get( L"KeyName",
                     0,
                     &v1,
                     0,
                     0 );
                if(hr) return ErrorMessage(hr,L"Get KeyName");

                hr = co->Get( L"Setting",
                     0,
                     &v2,
                     0,
                     0 );
                if(hr) return ErrorMessage(hr,L"Get Setting");

                if(!wcscmp(L"PasswordComplexity",v1.bstrVal)) { spp.PasswordComplexity=v2.boolVal; continue; }
                if(!wcscmp(L"ClearTextPassword",v1.bstrVal)) { spp.ClearTextPassword=v2.boolVal; continue; }
                if(!wcscmp(L"ForceLogoffWhenHourExpire",v1.bstrVal)) { spp.ForceLogoffWhenHourExpire=v2.boolVal; continue; }
                if(!wcscmp(L"RequireLogonToChangePassword",v1.bstrVal)) { spp.RequireLogonToChangePassword=v2.boolVal;  continue; }


    }
    return L"OK";
}


int _tmain(int argc, _TCHAR* argv[])
{
        CString strError;
        Struct_PolicyPassword spp;
        strError = GetWMIInformation(spp);

        wprintf(L"%s\n",strError.GetBuffer());

        cout << "spp.MaximumPasswordAge:" << spp.MaximumPasswordAge << endl;
        cout << "spp.MinimumPasswordAge:" << spp.MinimumPasswordAge << endl;
        cout << "spp.LockoutBadCount:" << spp.LockoutBadCount << endl;
        cout << "spp.PasswordHistorySize:" << spp.PasswordHistorySize << endl;
        cout << "spp.MinimumPasswordLength:" << spp.MinimumPasswordLength << endl;
        cout << "spp.PasswordComplexity:" << spp.PasswordComplexity << endl;
        cout << "spp.ClearTextPassword:" << spp.ClearTextPassword << endl;
        cout << "spp.ForceLogoffWhenHourExpire:" << spp.ForceLogoffWhenHourExpire << endl;
        cout << "spp.RequireLogonToChangePassword:" << spp.RequireLogonToChangePassword << endl;

        return 0;
}


Данные политики пароля выводятся только в том случае, если машина состоит в домене.
Данный код С++ является аналогом кода на VBS, который я приводил выше.

Автор: xvr 5.7.2010, 08:42
Цитата(racner @  4.7.2010,  21:36 Найти цитируемый пост)
Данный код С++ является аналогом кода на VBS
Справедливости ради замечу, что не совсем аналогом - метод логина в WMI немного другой: С++ код использует класс WbemLocator, а VB moniker, но результат тот же  smile 


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)