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


Автор: GremlinProg 6.11.2008, 06:49
Собственно, проблема в развернутом виде: программно добавить текущего пользователя (у него подразумеваются права админа) в список правила политики безопасности "Закрепление страниц в памяти", т.е. сделать с использованием SecurityAPI то, что мы обычно делаем ручками: Пуск -- Панель управления -- Администрирование -- Локальная политика безопасности -- Параметры безопасности -- Локальные политики -- назначение прав пользователя -- закрепление страниц в памяти -- Добавить пользователя или группу и т.д.

конечно, политика начнет функционировать только после перезагрузки, это не критично, главное за пользователя выставить это правило в системе, если попытка включить привилегию SeLockMemoryPrivilege не прошла.

программа работает с физической памятью, поэтому без этой привилегии ей делать нечего.

да, операционка, конечно, ХР.

Автор: Pulse69 7.11.2008, 16:49
Вот как-то так. Если где есть косяки, прошу сильно не пинать. 

Код

#include <windows.h>
#include <ntsecapi.h>
#include <Sddl.h>


#ifndef STATUS_SUCCESS
    #define STATUS_SUCCESS 0
#endif


void FreeTokenUser(TOKEN_USER* token_ptr)
{
    if(token_ptr)
    {
        operator delete(token_ptr);
    }
}

//------------------------------------------------------------------------
//      Получает пользователя определённого токена безопасности
//
//  IN:
//      hToken - токен безопасности
//      
//  RETURNS:
//      Указатель на токен или NULL в случае ошибки.
//      За удаление отвечает вызывающая функция.
//      используйте free_token_user
//------------------------------------------------------------------------
TOKEN_USER* GetTokenUser(HANDLE hToken)
{    
    TOKEN_USER* pTokUser = NULL;
    DWORD dwLength;

    //  Узнаём размер, необходимый для получения SID.
    if(!GetTokenInformation( hToken, TokenUser, NULL, 0, &dwLength ) 
        && GetLastError()==ERROR_INSUFFICIENT_BUFFER )
    {
        //  выделяем память для SID
        pTokUser = (TOKEN_USER*) operator new (dwLength);        

        //  Получаем SID.
        if(!GetTokenInformation( hToken, TokenUser, 
            pTokUser, dwLength, &dwLength ) )
        {            
            FreeTokenUser(pTokUser);
            pTokUser = NULL;
        }
    }

    return pTokUser;
}

void FreeSidInformation(PSID psid)
{
    if(psid)
    {
        operator delete (psid);
    }
}

PSID GetSIDInformation (const wchar_t* server, const wchar_t* AccountName)
{
    PSID psid    = NULL;
    DWORD dwSize = 0;

    TCHAR *buf  = NULL;
    DWORD dwBuf = 0;

    SID_NAME_USE siu;

    //    Узнаем необходимые размеры буферов
    LookupAccountName( server,
        AccountName,
        NULL,
        &dwSize,
        NULL,
        &dwBuf,
        &siu );

    //    Выделим память под буферы
    psid = operator new ( dwSize );//    За освобождение этого указателя отвечает вызывающая функция
    buf  = (TCHAR*)operator new ( dwBuf*sizeof( TCHAR ) );

    //    Получим описатель безопасности
    if(!LookupAccountName( server,
        AccountName,
        psid,
        &dwSize,
        buf,
        &dwBuf,
        &siu ))
    {        
        FreeSidInformation(psid);
        psid = NULL;
    }

    //    нам не нужны имена доменов, в которых происходил поиск
    if( buf ) operator delete ( buf );

    return psid;
}



LSA_HANDLE GetPolicyHandle(const wchar_t *SystemName)
{
    LSA_OBJECT_ATTRIBUTES ObjectAttributes;
    USHORT SystemNameLength;
    LSA_UNICODE_STRING lusSystemName;
    NTSTATUS ntsResult;
    LSA_HANDLE lsahPolicyHandle;

    //    Инициализация
    ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));

    //    Инициализация
    wchar_t buffer[1024];
    if(SystemName != NULL)
    {
        wcscpy_s(buffer, sizeof(buffer)/sizeof(buffer[0]), SystemName);
    }

    SystemNameLength = (SystemName!=NULL)?static_cast<USHORT>(wcslen(SystemName)) : 0;
    lusSystemName.Buffer = (SystemName==NULL) ? NULL : buffer;
    lusSystemName.Length = SystemNameLength * sizeof(WCHAR);
    lusSystemName.MaximumLength = (SystemNameLength+1) * sizeof(WCHAR);

    // Get a handle to the Policy object.
    ntsResult = LsaOpenPolicy(
        &lusSystemName,    //Name of the target system.
        &ObjectAttributes, //Object attributes.
        POLICY_ALL_ACCESS, //Desired access permissions.
        &lsahPolicyHandle  //Receives the policy handle.
        );

    if (ntsResult != STATUS_SUCCESS)
    {
        // An error occurred. Display it as a win32 error code.
        return NULL;
    } 
    return lsahPolicyHandle;
}


bool InitLsaString( PLSA_UNICODE_STRING pLsaString,
                    LPCWSTR pwszString )
{
    DWORD dwLen = 0;    

    if (NULL == pLsaString)
        return FALSE;

    //    Длина строки
    if (NULL != pwszString) 
    {
        dwLen = static_cast<int>(wcslen(pwszString));
        if (dwLen > 0x7ffe)   // Слишком большая строка
            return FALSE;
    }

    // Сохраняем строку
    pLsaString->Buffer = (WCHAR *)pwszString;
    pLsaString->Length =  (USHORT)dwLen * sizeof(WCHAR);
    pLsaString->MaximumLength= (USHORT)(dwLen+1) * sizeof(WCHAR);

    return TRUE;
}




/*
 *  server - сервер, для которого устанавливается политика (NULL для локального)
 *  wacct  - учётная запись для которой устанавливается политика. 
 *           NULL   - для текущего пользователя.
 *  policy - имя политики
 *  add    - добавить или удалить политику
 */
BOOL SetPolicy(const wchar_t* server, const wchar_t *wacct, const wchar_t *policy, bool add)
{
    NTSTATUS ntsResult      = 0;
    PSID user_sid           = NULL;
    TOKEN_USER* token_user  = NULL;

    //    Получаем описатель безопасности для учётной записи
    if(wacct == NULL)
    {
        //  Учётная запись не указана. Получаем текущую
        HANDLE process_token = NULL;
        if(OpenProcessToken(GetCurrentProcess(),
            TOKEN_QUERY,
            &process_token))
        {
            token_user = GetTokenUser(process_token);
            if(token_user)
            {
                //  Описатель безопасности текущего пользователя
                user_sid = token_user->User.Sid;
            }
            CloseHandle(process_token);
        }
    }
    else
    {
        //  Получаем описатель безопасности для текущей учётной записи
        user_sid = GetSIDInformation(NULL, wacct);
    }

    //  Не нашли описатель пользвоателя
    if(user_sid == NULL)
    {
        return FALSE;
    }

    //    Создаём LSA-строку
    LSA_UNICODE_STRING lucPrivilege;
    if (!InitLsaString(&lucPrivilege, policy))
    {
        return FALSE;
    }

    //    Получаем дескриптор политик для компьютера
    LSA_HANDLE  ph = GetPolicyHandle( server );
    

    //    Добавляем политику
    if( add )
    {
        ntsResult = LsaAddAccountRights(ph, user_sid, &lucPrivilege, 1 );     
    }
    else
    {
        ntsResult = LsaRemoveAccountRights( ph, user_sid, FALSE, &lucPrivilege, 1 );
    }    

    //    закрываем описатель политики
    LsaClose( ph );

    //    удаляем память, выделенную под описатель безопасности УЗ
    if(wacct == NULL)
    {
        FreeTokenUser(token_user);        
    }
    else
    {
        FreeSidInformation(user_sid);
    }

    return (ntsResult == STATUS_SUCCESS) ? TRUE : FALSE;
}


int _tmain(int argc, _TCHAR* argv[])
{
    SetPolicy(NULL, NULL, L"SeLockMemoryPrivilege", true);
    return 0;
}



Автор: GremlinProg 7.11.2008, 19:19
Pulse69

большой спасибо
похоже это оно самое, +1
сейчас подправлю локализацию из юникода
потестирую и выложу общий вариант

Автор: GremlinProg 7.11.2008, 20:07
Проверил, работает!
код практически не менял, все корректно, просто подправил пару вызовов, чтобы его можно было использовать в обоих режимах локализации, и выделил инлайном в заголовочном файле:
Код

//////////////
//  policy.h
//

#include <ntsecapi.h>
#include <Sddl.h>


#ifndef STATUS_SUCCESS
    #define STATUS_SUCCESS 0
#endif

inline void FreeTokenUser(TOKEN_USER* token_ptr){
    if(token_ptr){
        operator delete(token_ptr);
    }
}
//------------------------------------------------------------------------
//      Получает пользователя определённого токена безопасности
//
//  IN:
//      hToken - токен безопасности
//      
//  RETURNS:
//      Указатель на токен или NULL в случае ошибки.
//      За удаление отвечает вызывающая функция.
//      используйте free_token_user
//------------------------------------------------------------------------
inline TOKEN_USER*GetTokenUser(HANDLE hToken){
    TOKEN_USER* pTokUser = NULL;
    DWORD dwLength;

    //  Узнаём размер, необходимый для получения SID.
    if(!GetTokenInformation( hToken, TokenUser, NULL, 0, &dwLength ) 
        && GetLastError()==ERROR_INSUFFICIENT_BUFFER )
    {
        //  выделяем память для SID
        pTokUser = (TOKEN_USER*) operator new (dwLength);        

        //  Получаем SID.
        if(!GetTokenInformation( hToken, TokenUser, 
            pTokUser, dwLength, &dwLength ) )
        {            
            FreeTokenUser(pTokUser);
            pTokUser = NULL;
        }
    }

    return pTokUser;
}
inline void FreeSidInformation(PSID psid){
    if(psid){
        operator delete (psid);
    }
}
inline PSID GetSIDInformation(LPCTSTR server,LPCTSTR AccountName){
    PSID psid    = NULL;
    DWORD dwSize = 0;

    TCHAR *buf  = NULL;
    DWORD dwBuf = 0;

    SID_NAME_USE siu;

    //    Узнаем необходимые размеры буферов
    ::LookupAccountName(
        server,
        AccountName,
        NULL,
        &dwSize,
        NULL,
        &dwBuf,
        &siu
    );
    //    Выделим память под буферы
    psid = operator new ( dwSize );//    За освобождение этого указателя отвечает вызывающая функция
    buf  = (TCHAR*)operator new ( dwBuf*sizeof( TCHAR ) );

    //    Получим описатель безопасности
    if( !LookupAccountName(server,AccountName,psid,&dwSize,buf,&dwBuf,&siu) ){        
        FreeSidInformation(psid);
        psid = NULL;
    }

    //    нам не нужны имена доменов, в которых происходил поиск
    if( buf ) operator delete ( buf );

    return psid;
}



inline LSA_HANDLE GetPolicyHandle(LPCWSTR SystemName){
    LSA_OBJECT_ATTRIBUTES ObjectAttributes;
    USHORT SystemNameLength;
    LSA_UNICODE_STRING lusSystemName;
    NTSTATUS ntsResult;
    LSA_HANDLE lsahPolicyHandle;

    //    Инициализация
    ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));

    //    Инициализация
    WCHAR buffer[1024];
    if(SystemName != NULL){
        wcsncpy(buffer,SystemName,sizeof(buffer)/sizeof(buffer[0]));
    }

    SystemNameLength = (SystemName != NULL)? (USHORT)wcslen(SystemName) : 0;
    lusSystemName.Buffer = (SystemName == NULL) ? NULL : buffer;
    lusSystemName.Length = SystemNameLength * sizeof(WCHAR);
    lusSystemName.MaximumLength = (SystemNameLength+1) * sizeof(WCHAR);

    // Get a handle to the Policy object.
    ntsResult = LsaOpenPolicy(
        &lusSystemName,    //Name of the target system.
        &ObjectAttributes, //Object attributes.
        POLICY_ALL_ACCESS, //Desired access permissions.
        &lsahPolicyHandle  //Receives the policy handle.
        );

    if (ntsResult != STATUS_SUCCESS)
    {
        // An error occurred. Display it as a win32 error code.
        return NULL;
    } 
    return lsahPolicyHandle;
}
inline bool InitLsaString(PLSA_UNICODE_STRING pLsaString,LPCWSTR pwszString){
    DWORD dwLen = 0;    

    if (NULL == pLsaString)
        return FALSE;

    //    Длина строки
    if (NULL != pwszString) 
    {
        dwLen = static_cast<int>(wcslen(pwszString));
        if (dwLen > 0x7ffe)   // Слишком большая строка
            return FALSE;
    }

    // Сохраняем строку
    pLsaString->Buffer = (WCHAR *)pwszString;
    pLsaString->Length =  (USHORT)dwLen * sizeof(WCHAR);
    pLsaString->MaximumLength= (USHORT)(dwLen+1) * sizeof(WCHAR);

    return TRUE;
}
/*
 *  server - сервер, для которого устанавливается политика (NULL для локального)
 *  wacct  - учётная запись для которой устанавливается политика. NULL   - для текущего пользователя.
 *  policy - имя политики
 *  add    - добавить или удалить политику
 */
inline BOOL SetPolicy(LPCWSTR server, LPCTSTR wacct, LPCWSTR policy, bool add){
    NTSTATUS ntsResult        = 0;
    PSID user_sid            = NULL;
    TOKEN_USER* token_user    = NULL;

    //    Получаем описатель безопасности для учётной записи
    if(wacct == NULL)
    {
        //  Учётная запись не указана. Получаем текущую
        HANDLE process_token = NULL;
        if(OpenProcessToken(GetCurrentProcess(),
            TOKEN_QUERY,
            &process_token))
        {
            token_user = GetTokenUser(process_token);
            if(token_user)
            {
                //  Описатель безопасности текущего пользователя
                user_sid = token_user->User.Sid;
            }
            CloseHandle(process_token);
        }
    }
    else
    {
        //  Получаем описатель безопасности для текущей учётной записи
        user_sid = GetSIDInformation(NULL, wacct);
    }

    //  Не нашли описатель пользвоателя
    if(user_sid == NULL)
    {
        return FALSE;
    }

    //    Создаём LSA-строку
    LSA_UNICODE_STRING lucPrivilege;
    if (!InitLsaString(&lucPrivilege, policy))
    {
        return FALSE;
    }

    //    Получаем дескриптор политик для компьютера
    LSA_HANDLE  ph = GetPolicyHandle( server );
    

    //    Добавляем политику
    if( add )
    {
        ntsResult = LsaAddAccountRights(ph, user_sid, &lucPrivilege, 1 );     
    }
    else
    {
        ntsResult = LsaRemoveAccountRights( ph, user_sid, FALSE, &lucPrivilege, 1 );
    }    

    //    закрываем описатель политики
    LsaClose( ph );

    //    удаляем память, выделенную под описатель безопасности УЗ
    if(wacct == NULL)
    {
        FreeTokenUser(token_user);        
    }
    else
    {
        FreeSidInformation(user_sid);
    }

    return (ntsResult == STATUS_SUCCESS) ? TRUE : FALSE;
}

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