[Win32] [C++] CreateProcessAsUser – #3 ソース

小出しにしてきたプログラムの全貌です。ファイルは 5 つに分けました。
2 月のプログラムに、幾つかの機能を加えてあります。1000 行近くまで膨らんでしまった・・・。

  • main.cpp – エントリ ポイント、引数のパース
  • logue.cpp – メイン ルーチン
  • priv.cpp – 特権関係
  • dacl.cpp – DACL 関係
  • logue.h – 共通ヘッダー

(2014/12/29 追記)
HTML として貼り付けているだけと読みづらいので (検索でヒットしやすいというメリットはありますが・・)、ソースを GitHub に置きました。Makefile も作りましたので、Visual Studio のコマンド プロンプトから nmake コマンドをパラメーターなしで実行するだけでビルドできます。

https://github.com/msmania/logue

main.cpp

//
// main.cpp
//

#include <iostream>
#include <stdio.h>
#include <locale.h>
#include <Windows.h>

#include "logue.h"

using namespace std;

/*

Usage: logue -runas <user> <password> <command>
       logue -priv Enum
       logue -priv Add <privilege>
       logue -priv Check <privilege>
       logue -priv Enable <privilege>
       logue -priv Disable <privilege>

Example:
    logue domain\user password "c:\windows\system32\notepad.exe c:\temp\temp.txt"
    logue -priv check SeSecurityPrivilege

Privilege: http://msdn.microsoft.com/en-us/library/bb530716.aspx

*/

void ShowUsage() {
    wcout << L"\nUsage: logue -runas <user> <password> <command>" << endl;
    wcout << L"       logue -priv All" << endl;
    wcout << L"       logue -priv Enum" << endl;
    wcout << L"       logue -priv Add <privilege>" << endl;
    wcout << L"       logue -priv Check <privilege>" << endl;
    wcout << L"       logue -priv Enable <privilege>" << endl;
    wcout << L"       logue -priv Disable <privilege>" << endl << endl;
    wcout << L"Example:" << endl;
    wcout << L"    logue -runas domain\\user password \"c:\\windows\\system32\\notepad.exe c:\\temp\\temp.txt\"" << endl;
    wcout << L"    logue -priv check SeSecurityPrivilege" << endl << endl;
    wcout << L"Privilege:
http://msdn.microsoft.com/en-us/library/bb530716.aspx" << endl << endl;
}

#define MAX_COMMAND 16

static wchar_t upperstr[MAX_COMMAND+1];
const wchar_t *ToUpper(const wchar_t *s) {
    for ( int i=0 ; i<MAX_COMMAND+1 ; ++i ) {
        upperstr[i]= toupper(s[i]);
        if ( s[i]==0 )
            return upperstr;
    }
    upperstr[MAX_COMMAND]= 0;
    return upperstr;
}

int wmain(int argc, wchar_t *argv[]) {
    _wsetlocale(LC_ALL, L"");
   
    if ( argc<3 ) {
        ShowUsage();
        return ERROR_INVALID_PARAMETER;
    }

    LPCWSTR Command= ToUpper(argv[1]);
    if ( wcscmp(Command, L"-RUNAS")==0 ) {
        if ( argc<5 ) {
            ShowUsage();
            return ERROR_INVALID_PARAMETER;
        }

        RunAs(argv[2], argv[3], argv[4]);
    }
    else if ( wcscmp(Command, L"-PRIV")==0 ) {
        HANDLE Token= NULL;
        if ( !OpenProcessToken(GetCurrentProcess(),
                               TOKEN_ALL_ACCESS , &Token) ) {
            wprintf(L"OpenProcessToken failed – 0x%08x\n", GetLastError());
            return 0;
        }

        Command= ToUpper(argv[2]);
        if ( wcscmp(Command, L"ENUM")==0 )
            EnumPrivileges(Token, FALSE);
        else if ( wcscmp(Command, L"ALL")==0 )
            EnumPrivileges(Token, TRUE);
        else if ( argc>=4 && wcscmp(Command, L"ADD")==0 )
            AddPrivilege(Token, argv[3]);
        else if ( argc>=4 && wcscmp(Command, L"CHECK")==0 ) {
            LONG Ret= 0;
            if ( CheckPrivilege(Token, argv[3], &Ret) )
                wprintf(L"%s is %s.\n", argv[3],
                    Ret>0 ? L"ENABLED" :
                    Ret<0 ? L"NOT ASSIGNED" : L"DISABLED");
        }
        else if ( argc>=4 && wcscmp(Command, L"ENABLE")==0 ) {
            if ( EnablePrivilege(Token, argv[3], TRUE) )
                EnumPrivileges(Token, FALSE);
        }
        else if ( argc>=4 && wcscmp(Command, L"DISABLE")==0 ) {
            if ( EnablePrivilege(Token, argv[3], FALSE) )
                EnumPrivileges(Token, FALSE);
        }
        else {
            wprintf(L"Bad command – %s\n", argv[1]);
            return ERROR_BAD_COMMAND;
        }

        if ( Token ) CloseHandle(Token);
    }
    else {
        ShowUsage();
        wprintf(L"Unknown command – %s\n", argv[1]);
        return ERROR_INVALID_PARAMETER;
    }

    return 0;
}

logue.cpp

//
// logue.cpp
//
// base sample:
//
http://msdn.microsoft.com/en-us/library/aa379608(v=vs.85).aspx
//

#include <windows.h>
#include <stdio.h>

#include "logue.h"

VOID RunAs(LPWSTR inUser, LPWSTR inPW, LPWSTR inCommand) {
    HANDLE CallerToken= NULL;
    HANDLE CalleeToken= NULL;
    HWINSTA WinstaOld= NULL;
    HWINSTA Winsta0= NULL;
    HDESK Desktop= NULL;
    PSID LogonSid= NULL;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LONG PrivCheck= 0;
   
    if ( !OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS,
            &CallerToken) ) {
        wprintf(L"OpenProcessToken failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }
   
    CheckPrivilege(CallerToken, SE_INCREASE_QUOTA_NAME, &PrivCheck);
    if ( PrivCheck<0 )
        wprintf(L"CreateProcessAsUser requires %s.  Check the user’s privileges.\n", SE_INCREASE_QUOTA_NAME);

    CheckPrivilege(CallerToken, SE_ASSIGNPRIMARYTOKEN_NAME, &PrivCheck);
    if ( PrivCheck<0 )
        wprintf(L"CreateProcessAsUser requires %s.  Check the user’s privileges.\n", SE_ASSIGNPRIMARYTOKEN_NAME);
   
    if ( !LogonUser(inUser, NULL, inPW, LOGON32_LOGON_INTERACTIVE,
            LOGON32_PROVIDER_DEFAULT, &CalleeToken) ) {
        wprintf(L"LogonUser failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }

#ifdef _GUI
    Winsta0= OpenWindowStation(L"winsta0", FALSE, READ_CONTROL|WRITE_DAC);
    if ( !Winsta0 ) {
        wprintf(L"OpenWindowStation failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }

    WinstaOld= GetProcessWindowStation();
    if ( !SetProcessWindowStation(Winsta0) ) {
        wprintf(L"SetProcessWindowStation failed – 0x%08x\n",
                GetLastError());
        goto Cleanup;
    }
    Desktop= OpenDesktop(L"default", 0, FALSE,
        READ_CONTROL|WRITE_DAC|DESKTOP_WRITEOBJECTS|DESKTOP_READOBJECTS);
    SetProcessWindowStation(WinstaOld);
    if ( !Desktop ) {
        wprintf(L"OpenDesktop failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }
   
    if ( !GetLogonSidFromToken(CalleeToken, &LogonSid) )
        goto Cleanup;
   
#ifdef _TRACING
    wprintf(L"PID      : 0x%x\n", GetCurrentProcessId());
    wprintf(L"HWINSTA  : 0x%x\n", Winsta0);
    wprintf(L"HDESK    : 0x%x\n", Desktop);
    wprintf(L"Logon SID: %p\n", LogonSid);
    wprintf(L"—–\n");
    getwchar();
#endif

    if ( !AddAceToWindowStation(Winsta0, LogonSid) ) {
        wprintf(L"AddAceToWindowStation failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }

    if ( !AddAceToDesktop(Desktop, LogonSid) ) {
        wprintf(L"AddAceToDesktop failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }
#endif
   
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb= sizeof(STARTUPINFO);

#ifdef _GUI
    si.lpDesktop= L"winsta0\\default";
#else
    si.lpDesktop= L"";
#endif
   
    if ( !ImpersonateLoggedOnUser(CalleeToken) ) {
        wprintf(L"ImpersonateLoggedOnUser failed – 0x%08x\n",
                GetLastError());
        goto Cleanup;
    }

    if ( !CreateProcessAsUser(CalleeToken, NULL, inCommand, NULL, NULL,
                              FALSE, 0, NULL, NULL, &si, &pi) ) {
        wprintf(L"CreateProcessAsUser failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }
   
    WaitForSingleObject(pi.hProcess, INFINITE);
   
    RevertToSelf();

#ifdef _GUI
    RemoveAccessAllowedAcesBasedSID(Winsta0, LogonSid);
    RemoveAccessAllowedAcesBasedSID(Desktop, LogonSid);
#endif
   
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

Cleanup:
    if ( LogonSid ) HeapFree(GetProcessHeap(), 0, LogonSid);
    if ( Winsta0 ) CloseWindowStation(Winsta0);
    if ( Desktop ) CloseDesktop(Desktop);
    if ( CalleeToken ) CloseHandle(CalleeToken);
    if ( CallerToken ) CloseHandle(CallerToken);
}

priv.cpp

//
// priv.cpp
//

#include <windows.h>
#include <NTSecAPI.h>
#include <stdio.h>
#include <strsafe.h>

#include "logue.h"

#define MAX_PRIVNAME 32
#define MAX_PRIVSCAN 256

#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth

struct PRIVILAGENAME_MAPPING {
    WCHAR SymbolName[MAX_PRIVNAME];
    WCHAR PrivilegeName[MAX_PRIVNAME];
};

const PRIVILAGENAME_MAPPING PrivilegeNameMapping[]= {
    { L"SE_CREATE_TOKEN_NAME", SE_CREATE_TOKEN_NAME },
    { L"SE_ASSIGNPRIMARYTOKEN_NAME", SE_ASSIGNPRIMARYTOKEN_NAME },
    { L"SE_LOCK_MEMORY_NAME", SE_LOCK_MEMORY_NAME },
    { L"SE_INCREASE_QUOTA_NAME", SE_INCREASE_QUOTA_NAME },
    { L"SE_UNSOLICITED_INPUT_NAME", SE_UNSOLICITED_INPUT_NAME }, // no LUID?
    { L"SE_MACHINE_ACCOUNT_NAME", SE_MACHINE_ACCOUNT_NAME },
    { L"SE_TCB_NAME", SE_TCB_NAME },
    { L"SE_SECURITY_NAME", SE_SECURITY_NAME },
    { L"SE_TAKE_OWNERSHIP_NAME", SE_TAKE_OWNERSHIP_NAME },
    { L"SE_LOAD_DRIVER_NAME", SE_LOAD_DRIVER_NAME },
    { L"SE_SYSTEM_PROFILE_NAME", SE_SYSTEM_PROFILE_NAME },
    { L"SE_SYSTEMTIME_NAME", SE_SYSTEMTIME_NAME },
    { L"SE_PROF_SINGLE_PROCESS_NAME", SE_PROF_SINGLE_PROCESS_NAME },
    { L"SE_INC_BASE_PRIORITY_NAME", SE_INC_BASE_PRIORITY_NAME },
    { L"SE_CREATE_PAGEFILE_NAME", SE_CREATE_PAGEFILE_NAME },
    { L"SE_CREATE_PERMANENT_NAME", SE_CREATE_PERMANENT_NAME },
    { L"SE_BACKUP_NAME", SE_BACKUP_NAME },
    { L"SE_RESTORE_NAME", SE_RESTORE_NAME },
    { L"SE_SHUTDOWN_NAME", SE_SHUTDOWN_NAME },
    { L"SE_DEBUG_NAME", SE_DEBUG_NAME },
    { L"SE_AUDIT_NAME", SE_AUDIT_NAME },
    { L"SE_SYSTEM_ENVIRONMENT_NAME", SE_SYSTEM_ENVIRONMENT_NAME },
    { L"SE_CHANGE_NOTIFY_NAME", SE_CHANGE_NOTIFY_NAME },
    { L"SE_REMOTE_SHUTDOWN_NAME", SE_REMOTE_SHUTDOWN_NAME },
    { L"SE_UNDOCK_NAME", SE_UNDOCK_NAME },
    { L"SE_SYNC_AGENT_NAME", SE_SYNC_AGENT_NAME },
    { L"SE_ENABLE_DELEGATION_NAME", SE_ENABLE_DELEGATION_NAME },
    { L"SE_MANAGE_VOLUME_NAME", SE_MANAGE_VOLUME_NAME },
    { L"SE_IMPERSONATE_NAME", SE_IMPERSONATE_NAME },
    { L"SE_CREATE_GLOBAL_NAME", SE_CREATE_GLOBAL_NAME },
    { L"SE_TRUSTED_CREDMAN_ACCESS_NAME", SE_TRUSTED_CREDMAN_ACCESS_NAME },
    { L"SE_RELABEL_NAME", SE_RELABEL_NAME },
    { L"SE_INC_WORKING_SET_NAME", SE_INC_WORKING_SET_NAME },
    { L"SE_TIME_ZONE_NAME", SE_TIME_ZONE_NAME },
    { L"SE_CREATE_SYMBOLIC_LINK_NAME", SE_CREATE_SYMBOLIC_LINK_NAME },
    { L"", L"" }
};

BOOL LookupPrivilegeName(LPCWSTR SystemName,
                        CONST PLUID Luid, LPCWSTR *SymbolName,
                        LPWSTR PrivilegeName, LPDWORD PrivilegeNameLength,
                        LPWSTR DisplayName, LPDWORD DisplayNameLength,
                        BOOL NoErrMsg) {
    BOOL Ret= FALSE;
    DWORD LanguageId;
    int Index= -1;

    Ret= LookupPrivilegeName(NULL, Luid, PrivilegeName, PrivilegeNameLength);
    if ( !Ret ) {
        if ( GetLastError()!=ERROR_INSUFFICIENT_BUFFER && !NoErrMsg )
            wprintf(L"LookupPrivilegeName failed – 0x%08x\n",
                    GetLastError());
        goto cleanup;
    }

    Ret= LookupPrivilegeDisplayName(NULL,
        PrivilegeName, DisplayName, DisplayNameLength, &LanguageId);
    if ( !Ret ) {
        if ( GetLastError()!=ERROR_INSUFFICIENT_BUFFER && !NoErrMsg )
            wprintf(L"LookupPrivilegeDisplayName failed – 0x%08x\n",
                    GetLastError());
        goto cleanup;
    }

    Ret= FALSE;
    const PRIVILAGENAME_MAPPING *p=PrivilegeNameMapping;
    for ( Index=0 ; p->SymbolName[0]!=0 ; ++p, ++Index ) {
        if ( wcscmp(PrivilegeName, p->PrivilegeName)==0 ) {
            Ret= TRUE;
            break;
        }
    }

    if ( Ret )
        *SymbolName= PrivilegeNameMapping[Index].SymbolName;
    else if ( NoErrMsg )
        wprintf(L"%s not found\n", PrivilegeName);

cleanup:
    return Ret;
}

BOOL LookupPrivilegeValueEx(LPCWSTR SystemName, LPCWSTR Name, PLUID Luid) {
    BOOL Ret= LookupPrivilegeValue(SystemName, Name, Luid);
    if ( !Ret && GetLastError()==ERROR_NO_SUCH_PRIVILEGE ) {
        const PRIVILAGENAME_MAPPING *p;
        for ( p=PrivilegeNameMapping ; p->SymbolName[0]!=0 ; ++p ) {
            if ( wcscmp(Name, p->SymbolName)==0 )
                return LookupPrivilegeValue(SystemName,
                       p->PrivilegeName, Luid);
        }
        SetLastError(ERROR_NO_SUCH_PRIVILEGE);
        Ret= FALSE;
    }
    return Ret;
}

VOID EnumPrivileges(HANDLE Token, BOOL All) {
    BOOL Ret= FALSE;
    DWORD TokenLength= 0;
    PTOKEN_PRIVILEGES TokenPriv= NULL;
    DWORD PrivilegeNameLength= 256;
    DWORD DisplayNameLength= 256;
    PWCHAR PrivilegeName= NULL;
    PWCHAR DisplayName= NULL;
    LPCWCHAR SymbolName= NULL;
   
    // LUID = Locally Unique Identifier
    wprintf(L"——————————————————————————————————-\n");
    wprintf(L"   LUID                Symbol                           PrivilegeName                    DisplayName\n");
    wprintf(L"——————————————————————————————————-\n");

    if ( !All ) {
        if ( !GetTokenInformation(Token, TokenPrivileges,
                NULL, 0, &TokenLength) &&
                GetLastError()!=ERROR_INSUFFICIENT_BUFFER ) {
            wprintf(L"GetTokenInformation (size check) failed – 0x%08x\n",
                    GetLastError());
            goto cleanup;
        }

        TokenPriv= (PTOKEN_PRIVILEGES)HeapAlloc(GetProcessHeap(),
                    0, TokenLength);
        if ( !TokenPriv ) {
            wprintf(L"HeapAlloc failed – 0x%08x\n", GetLastError());
            goto cleanup;
        }

        if ( !GetTokenInformation(Token, TokenPrivileges, TokenPriv,
                  TokenLength, &TokenLength) ) {
            wprintf(L"GetTokenInformation failed – 0x%08x\n",
                    GetLastError());
            goto cleanup;
        }

    }
    else {
        TokenPriv= (PTOKEN_PRIVILEGES)HeapAlloc(GetProcessHeap(), 0,
            sizeof(DWORD)+sizeof(LUID_AND_ATTRIBUTES)*MAX_PRIVSCAN);
        if ( !TokenPriv ) {
            wprintf(L"HeapAlloc failed – 0x%08x\n", GetLastError());
            goto cleanup;
        }
       
        TokenPriv->PrivilegeCount= MAX_PRIVSCAN;
        for (  LONGLONG i=0 ; i<MAX_PRIVSCAN ; ++i ) {
            TokenPriv->Privileges[i].Luid= *(PLUID)&i;
            TokenPriv->Privileges[i].Attributes= 0;
        }
    }
   
    for ( DWORD i=0 ; i<TokenPriv->PrivilegeCount ; ++i ) {
        do {
            if ( PrivilegeName ) delete [] PrivilegeName;
            if ( DisplayName ) delete [] DisplayName;

            PrivilegeName= new WCHAR[PrivilegeNameLength];
            DisplayName= new WCHAR[DisplayNameLength];

            Ret= LookupPrivilegeName(NULL,
                &TokenPriv->Privileges[i].Luid, &SymbolName,
                    PrivilegeName, &PrivilegeNameLength,
                    DisplayName, &DisplayNameLength,
                    All);
        } while( !Ret && GetLastError()==ERROR_INSUFFICIENT_BUFFER );

        if ( Ret ) {
            WCHAR Mark= 0;
            if ( All ) {
                LONG l= 0;
                CheckPrivilege(Token, PrivilegeName, &l);
                Mark= l==0 ? Mark= ‘X’ :
                    l>0 ? Mark= ‘O’ : ‘-‘;
            }
            else {
                Mark= TokenPriv->Privileges[i].Attributes&SE_PRIVILEGE_ENABLED ? L’O’ : L’X’;
            }

            wprintf(L" %c 0x%08x`%08x %-32s %-32s %s\n", Mark,
                TokenPriv->Privileges[i].Luid.HighPart,
                TokenPriv->Privileges[i].Luid.LowPart,
                SymbolName,
                PrivilegeName,
                DisplayName);
        }
    }

cleanup:
    if ( PrivilegeName ) delete [] PrivilegeName;
    if ( DisplayName ) delete [] DisplayName;
    if ( TokenPriv ) HeapFree(GetProcessHeap(), 0, TokenPriv);
}

// http://msdn.microsoft.com/en-us/library/ms722492(v=VS.85) InitLsaString
//
http://msdn.microsoft.com/en-us/library/ms721874(v=vs.85).aspx
// http://msdn.microsoft.com/en-us/library/ms721863(v=vs.85).aspx
BOOL AddPrivilege(HANDLE Token, LPCWSTR PrivilegeName) {
    NTSTATUS Ret= 0;
    LSA_OBJECT_ATTRIBUTES ObjectAttributes;
    LSA_HANDLE PolicyHandle= NULL;
    PSID Sid= NULL;
    LSA_UNICODE_STRING Privilege[1];
    size_t PrivNameLength= 0;
    PTOKEN_USER CurrentUserSid= NULL;
    DWORD CurrentUserSidLength= 0;

    // get current user SID from the token
    if ( !GetTokenInformation(Token, TokenUser, NULL, 0,
            &CurrentUserSidLength) &&
            GetLastError()!=ERROR_INSUFFICIENT_BUFFER ) {
        wprintf(L"GetTokenInformation (size check) failed – 0x%08x\n",
                GetLastError());
        goto cleanup;
    }

    CurrentUserSid= (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0,
                    CurrentUserSidLength);
    if ( !CurrentUserSid ) {
        wprintf(L"HeapAlloc failed – 0x%08x\n", GetLastError());
        goto cleanup;
    }

    if ( !GetTokenInformation(Token, TokenUser, CurrentUserSid,
            CurrentUserSidLength, &CurrentUserSidLength) ) {
        wprintf(L"GetTokenInformation failed – 0x%08x\n", GetLastError());
        goto cleanup;
    }
   
    PrivNameLength= StringCchLength(PrivilegeName,
        MAX_PRIVNAME, &PrivNameLength);
    Privilege[0].Buffer= (PWCHAR)PrivilegeName;
    Privilege[0].Length= PrivNameLength*sizeof(WCHAR);
    Privilege[0].MaximumLength= (PrivNameLength+1)*sizeof(WCHAR);
   
    ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
    Ret= LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_ALL_ACCESS,
                       &PolicyHandle);
    if ( Ret!=STATUS_SUCCESS ) {
        wprintf(L"LsaOpenPolicy failed – 0x%08x\n",
                LsaNtStatusToWinError(Ret));
        goto cleanup;
    }

    StringCchLength(PrivilegeName, MAX_PRIVNAME, &PrivNameLength);
    Privilege[0].Buffer= (PWCHAR)PrivilegeName;
    Privilege[0].Length= PrivNameLength*sizeof(WCHAR);
    Privilege[0].MaximumLength= (PrivNameLength+1)*sizeof(WCHAR);

    Ret= LsaAddAccountRights(PolicyHandle,
        CurrentUserSid->User.Sid, Privilege, 1);;
    if ( Ret!=STATUS_SUCCESS ) {
        wprintf(L"LsaAddAccountRights failed – 0x%08x\n",
            LsaNtStatusToWinError(Ret));
        goto cleanup;
    }

    wprintf(L"Privilege ‘%s’ was assigned successfully.\n", PrivilegeName);
    wprintf(L"To apply it to the token, re-log on the system.\n");

cleanup:
    if ( PolicyHandle ) LsaClose(PolicyHandle);   
    if ( CurrentUserSid ) HeapFree(GetProcessHeap(), 0, CurrentUserSid);

    return Ret==STATUS_SUCCESS;
}

// >0 Enabled
// =0 Disabled
// <0 Not assigned

BOOL CheckPrivilege(HANDLE Token, LPCWSTR PrivilegeName, LPLONG Privileged) {
    LUID luid;
    if ( !LookupPrivilegeValueEx(NULL, PrivilegeName, &luid) ){
        wprintf(L"LookupPrivilegeValue failed – 0x%08x\n", GetLastError());
        return FALSE;
    }

    PRIVILEGE_SET PrivilegeSet;
    PrivilegeSet.Control= 0;
    PrivilegeSet.PrivilegeCount= 1;
    PrivilegeSet.Privilege[0].Luid= luid;
    PrivilegeSet.Privilege[0].Attributes= 0; // not used

    BOOL Check;
    if ( !PrivilegeCheck(Token, &PrivilegeSet, &Check) ) {
        wprintf(L"PrivilegeCheck failed – 0x%08x\n", GetLastError());
        return FALSE;
    }
   
    if ( Check )
        *Privileged= 1;
    else {
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount= 1;
        tp.Privileges[0].Luid= luid;
        tp.Privileges[0].Attributes= 0;

        if ( !AdjustTokenPrivileges(Token, FALSE, &tp,
                sizeof(TOKEN_PRIVILEGES), NULL, NULL) ) {
            wprintf(L"AdjustTokenPrivileges failed – 0x%08x\n",
                    GetLastError());
            return FALSE;
        }

        *Privileged= (GetLastError()==ERROR_NOT_ALL_ASSIGNED) ? -1 : 0;
    }

    return TRUE;
}
 
BOOL EnablePrivilege(HANDLE Token, LPWSTR Name, BOOL Enabled) {
    LUID luid;
    if ( !LookupPrivilegeValueEx(NULL, Name, &luid) ) {
        wprintf(L"LookupPrivilegeValue failed – 0x%08x\n", GetLastError());
        return FALSE;
    }
   
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount= 1;
    tp.Privileges[0].Luid= luid;
    tp.Privileges[0].Attributes=
      Enabled ? SE_PRIVILEGE_ENABLED : 0;
      // not use SE_PRIVILEGE_REMOVED, just disable

    if ( !AdjustTokenPrivileges(Token, FALSE, &tp,
            sizeof(TOKEN_PRIVILEGES), NULL, NULL) ) {
        wprintf(L"AdjustTokenPrivileges failed – 0x%08x\n", GetLastError());
        return FALSE;
    }
   
    if ( GetLastError()==ERROR_NOT_ALL_ASSIGNED ) {
        wprintf(L"The process token does not have %s (%I64d).\n",
                Name, luid);
        return FALSE;
    }

    wprintf(L"%s (%I64d) is temporarily %s.\n", Name, luid,
        Enabled ? L"enabled" : L"disabled");

    return TRUE;
}

dacl.cpp

//
// dacl.cpp
//

#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>

#include "logue.h"

// add ACCESS_ALLOWED_ACEs of the specified SID to the object’s DACL
BOOL AddAccessAllowedAceBasedSID(HANDLE Object, PSID Sid, DWORD AceCount,
                                CONST DWORD AceFlags[],
                                CONST DWORD AccessMasks[]) {
    BOOL Ret= FALSE;
    SECURITY_INFORMATION DaclInfo= DACL_SECURITY_INFORMATION;
    PACL Acl= NULL; // no need to free
    PACL AclNew= NULL;
    PSECURITY_DESCRIPTOR Sd= NULL;
    PSECURITY_DESCRIPTOR SdNew= NULL;
    DWORD SdSize= 0;
    DWORD SdSizeNeeded= 0;
    ACL_SIZE_INFORMATION AclSizeInfo;
    DWORD AclSize= 0;
    BOOL DaclPresent;
    BOOL DaclDefaulted;

    //
    // Obtain DACL from the object.
    //
http://msdn.microsoft.com/en-us/library/aa379573
    //
    if ( !GetUserObjectSecurity(Object, &DaclInfo, Sd, 0, &SdSizeNeeded) ) {
        if ( GetLastError()!=ERROR_INSUFFICIENT_BUFFER )
            goto cleanup;
           
        Sd= (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
              HEAP_ZERO_MEMORY, SdSizeNeeded);
        if ( Sd==NULL ) goto cleanup;

        SdSize= SdSizeNeeded;
        if ( !GetUserObjectSecurity(Object, &DaclInfo, Sd, SdSize,
                &SdSizeNeeded) )
            goto cleanup;
    }

    // Obtain the DACL from the security descriptor.
    if ( !GetSecurityDescriptorDacl(Sd, &DaclPresent, &Acl, &DaclDefaulted) )
        goto cleanup;

    // Initialize.
    ZeroMemory(&AclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
    AclSizeInfo.AclBytesInUse = sizeof(ACL);
    if ( Acl ) {
        if (!GetAclInformation(Acl, (LPVOID)&AclSizeInfo,
               sizeof(ACL_SIZE_INFORMATION), AclSizeInformation) )
            goto cleanup;
    }

    // Create a new ACL
    // (original ACL + new ACCESS_ALLOWED_ACEs)
    AclSize= AclSizeInfo.AclBytesInUse +
        AceCount * (sizeof(ACCESS_ALLOWED_ACE) +
        GetLengthSid(Sid) – sizeof(DWORD));
    AclNew= (PACL)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AclSize);
    if ( AclNew==NULL ) goto cleanup;

    if ( !InitializeAcl(AclNew, AclSize, ACL_REVISION) )
        goto cleanup;

    // If DACL is present, copy all the ACEs to a new DACL.
    if ( DaclPresent && AclSizeInfo.AceCount ) {
        for ( DWORD i=0; i < AclSizeInfo.AceCount; ++i ) {
            PVOID Ace= NULL;
            if ( !GetAce(Acl, i, &Ace) ) goto cleanup;

            if (!AddAce(AclNew, ACL_REVISION, MAXDWORD, Ace,
                  ((PACE_HEADER)Ace)->AceSize) )
                goto cleanup;
        }
    }

    // Add new ACEs of specified SID to the DACL
    for ( DWORD i=0 ; i<AceCount ; ++i ) {
        if (!AddAccessAllowedAceEx(AclNew, ACL_REVISION, AceFlags[i],
                AccessMasks[i], Sid) )
            goto cleanup;
    }

    // Create a new security descriptor.
    // SECURITY_DESCRIPTOR_MIN_LENGTH is enough because
    // SetSecurityDescriptorDacl creates absolute security descriptor
    SdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
      HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH);
    if ( SdNew==NULL ) goto cleanup;

    if ( !InitializeSecurityDescriptor(SdNew, SECURITY_DESCRIPTOR_REVISION) )
        goto cleanup;

    // Set new DACL to the new security descriptor.
    // (this security descriptor becomes an absolute SD)
    if ( !SetSecurityDescriptorDacl(SdNew, TRUE, AclNew, FALSE) )
        goto cleanup;
   
#ifdef _TRACING
    wprintf(L"Original SD: %p\n", Sd);
    wprintf(L"New SD     : %p\n", SdNew);
    wprintf(L"–>\n");
    getwchar();
#endif

    // Set the new security descriptor for the desktop object.
    if (!SetUserObjectSecurity(Object, &DaclInfo, SdNew))
        goto cleanup;

    Ret= TRUE;

cleanup:
    if ( AclNew ) HeapFree(GetProcessHeap(), 0, AclNew);
    if ( Sd ) HeapFree(GetProcessHeap(), 0, Sd);
    if ( SdNew ) HeapFree(GetProcessHeap(), 0, SdNew);

    return Ret;
}

// add ACCESS_ALLOWED_ACEs of the specified SID to the object’s DACL
BOOL RemoveAccessAllowedAcesBasedSID(HANDLE Object, PSID Sid) {
    BOOL Ret= FALSE;
    SECURITY_INFORMATION DaclInfo= DACL_SECURITY_INFORMATION;
    PACL Acl= NULL; // no need to free
    PACL AclNew= NULL;
    PSECURITY_DESCRIPTOR Sd= NULL;
    PSECURITY_DESCRIPTOR SdNew= NULL;
    DWORD SdSize= 0;
    DWORD SdSizeNeeded= 0;
    ACL_SIZE_INFORMATION AclSizeInfo;
    DWORD AclSize= 0;
    BOOL DaclPresent;
    BOOL DaclDefaulted;

    //
    // Obtain DACL from the object.
    //
http://msdn.microsoft.com/en-us/library/aa379573
    //
    if ( !GetUserObjectSecurity(Object, &DaclInfo, Sd, 0, &SdSizeNeeded) ) {
        if ( GetLastError()!=ERROR_INSUFFICIENT_BUFFER )
            goto cleanup;
           
        Sd= (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
              HEAP_ZERO_MEMORY, SdSizeNeeded);
        if ( Sd==NULL ) goto cleanup;

        SdSize= SdSizeNeeded;
        if ( !GetUserObjectSecurity(Object, &DaclInfo, Sd, SdSize,
               &SdSizeNeeded) )
            goto cleanup;
    }

    // Obtain the DACL from the security descriptor.
    if ( !GetSecurityDescriptorDacl(Sd, &DaclPresent, &Acl, &DaclDefaulted) )
        goto cleanup;

    if ( !DaclPresent || !Acl || Acl->AceCount==0 ) {
        // nothing to do for Null DACL or Empty DACL
        //
http://technet.microsoft.com/ja-jp/query/aa379286
        Ret= TRUE;
        goto cleanup;
    }

    // Initialize.
    ZeroMemory(&AclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
    if (!GetAclInformation(Acl, (LPVOID)&AclSizeInfo,
           sizeof(ACL_SIZE_INFORMATION), AclSizeInformation) )
        goto cleanup;

    // Create an ACL copy
    AclSize= AclSizeInfo.AclBytesInUse;
    AclNew= (PACL)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AclSize);
    if ( AclNew==NULL ) goto cleanup;

    if ( !InitializeAcl(AclNew, AclSize, ACL_REVISION) )
        goto cleanup;
   
    // do not copy ACCESS_ALLOWED_ACEs of the specified SID
    if ( DaclPresent && AclSizeInfo.AceCount ) {
        for ( DWORD i=0; i < AclSizeInfo.AceCount; ++i ) {
            PVOID Ace= NULL;
            if ( !GetAce(Acl, i, &Ace) ) goto cleanup;
           
            if ( ((PACE_HEADER)Ace)->AceType==ACCESS_ALLOWED_ACE_TYPE &&
                    EqualSid(Sid, &((ACCESS_ALLOWED_ACE*)Ace)->SidStart) )
                continue;

            if (!AddAce(AclNew, ACL_REVISION, MAXDWORD, Ace,
                  ((PACE_HEADER)Ace)->AceSize) )
                goto cleanup;
        }
    }
   
    // Create a new security descriptor.
    // SECURITY_DESCRIPTOR_MIN_LENGTH is enough because
    // SetSecurityDescriptorDacl creates absolute security descriptor
    SdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
      HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH);
    if ( SdNew==NULL ) goto cleanup;

    if ( !InitializeSecurityDescriptor(SdNew, SECURITY_DESCRIPTOR_REVISION) )
        goto cleanup;

    // Set new DACL to the new security descriptor.
    // (this security descriptor becomes an absolute SD)
    if ( !SetSecurityDescriptorDacl(SdNew, TRUE, AclNew, FALSE) )
        goto cleanup;
   
#ifdef _TRACING
    wprintf(L"Original SD: %p\n", Sd);
    wprintf(L"New SD     : %p\n", SdNew);
    wprintf(L"–>\n");
    getwchar();
#endif

    // Set the new security descriptor for the desktop object.
    if (!SetUserObjectSecurity(Object, &DaclInfo, SdNew))
        goto cleanup;

    Ret= TRUE;

cleanup:
    if ( AclNew ) HeapFree(GetProcessHeap(), 0, AclNew);
    if ( Sd ) HeapFree(GetProcessHeap(), 0, Sd);
    if ( SdNew ) HeapFree(GetProcessHeap(), 0, SdNew);

    return Ret;
}

BOOL AddAceToDesktop(HDESK Desktop, PSID Sid) {
    CONST DWORD AccessMasks[1] = {
        DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
        DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD |
        DESKTOP_JOURNALPLAYBACK |
        DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP |
        STANDARD_RIGHTS_REQUIRED
    };

    DWORD AceFlags[1] = {0};

    return AddAccessAllowedAceBasedSID(Desktop, Sid,
      1, AceFlags, AccessMasks);
}

BOOL AddAceToWindowStation(HWINSTA Winsta, PSID Sid) {
    CONST DWORD AccessMasks[2] = {
        GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL,
        WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES |
        WINSTA_ACCESSCLIPBOARD |
        WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES |
        WINSTA_ACCESSGLOBALATOMS |
        WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN |
        STANDARD_RIGHTS_REQUIRED};

    CONST DWORD AceFlags[2] = {
        CONTAINER_INHERIT_ACE|INHERIT_ONLY_ACE|OBJECT_INHERIT_ACE,
        NO_PROPAGATE_INHERIT_ACE
    };   

    return AddAccessAllowedAceBasedSID(Winsta, Sid,
       2, AceFlags, AccessMasks);
}

BOOL GetLogonSidFromToken(HANDLE Token, PSID *outSid) {
    BOOL Ret= FALSE;
    DWORD TokenGroupLength= 0;
    DWORD SidLength= 0;
    PTOKEN_GROUPS TokenGroup= NULL;
    LPWSTR SidString= NULL;

    if ( !GetTokenInformation(Token, TokenGroups, (LPVOID)TokenGroup,
            0, &TokenGroupLength) &&
            GetLastError()!=ERROR_INSUFFICIENT_BUFFER ) {
        wprintf(L"GetTokenInformation (1st chance) failed – 0x%08x\n",
                GetLastError());
        goto Cleanup;
    }

    TokenGroup= (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
                 HEAP_ZERO_MEMORY, TokenGroupLength);
    if ( !TokenGroup ) {
        wprintf(L"HeapAlloc failed – 0x%08x\n", GetLastError());
        goto Cleanup;
    }

    if ( !GetTokenInformation(Token, TokenGroups, (LPVOID)TokenGroup,
            TokenGroupLength, &TokenGroupLength) ) {
        wprintf(L"GetTokenInformation failed (2nd chance) – 0x%08x\n",
          GetLastError());
        goto Cleanup;
    }

    //
    // SE_GROUP_LOGON_ID
    // The SID is a logon SID that identifies the logon session
    // associated with an access token.
    //
http://technet.microsoft.com/en-us/library/aa379624
    //
    for ( DWORD i=0 ; i<TokenGroup->GroupCount ; ++i ) {
        if ( SidString ) LocalFree(SidString);
        ConvertSidToStringSid(TokenGroup->Groups[i].Sid, &SidString);
        wprintf(L"SID: %s", SidString);

        if ( (TokenGroup->Groups[i].Attributes&SE_GROUP_LOGON_ID)
                ==SE_GROUP_LOGON_ID ) {
            SidLength= GetLengthSid(TokenGroup->Groups[i].Sid);

            *outSid= (PSID)HeapAlloc(GetProcessHeap(),
               HEAP_ZERO_MEMORY, SidLength);
            if ( *outSid==NULL ) {

                wprintf(L"HeapAlloc failed – 0x%08x\n", GetLastError());
                goto Cleanup;
            }

            if ( !CopySid(SidLength, *outSid, TokenGroup->Groups[i].Sid) ) {
                wprintf(L"CopySid failed – 0x%08x\n", GetLastError());
                HeapFree(GetProcessHeap(), 0, (LPVOID)*outSid);
                goto Cleanup;
            }

            wprintf(L" (Logon)\n");
            break;
        }
        else
            wprintf(L"\n");
    }
   
    Ret= TRUE;

Cleanup:
    if ( SidString ) LocalFree(SidString);
    if ( TokenGroup ) HeapFree(GetProcessHeap(), 0, TokenGroup);
    return Ret;
}

logue.h

//
// logue.h
//

#pragma once

#define _GUI
#define _TRACING

VOID EnumPrivileges(HANDLE Token, BOOL All);
BOOL AddPrivilege(HANDLE Token, LPCWSTR PrivilegeName);
BOOL EnablePrivilege(HANDLE Token, LPWSTR Name, BOOL Enabled);
BOOL CheckPrivilege(HANDLE Token, LPCWSTR PrivilegeName, LPLONG Privileged);

BOOL GetLogonSidFromToken(HANDLE Token, PSID *outSid);
BOOL AddAceToWindowStation(HWINSTA Winsta, PSID Sid);
BOOL AddAceToDesktop(HDESK Desktop, PSID Sid);
BOOL RemoveAccessAllowedAcesBasedSID(HANDLE Object, PSID Sid);

VOID RunAs(LPWSTR inUser, LPWSTR inPW, LPWSTR inCommand);

広告

One Response to [Win32] [C++] CreateProcessAsUser – #3 ソース

  1. ピンバック: [Win32] [C++] LogonUser と CreateProcessAsUser « すなのかたまり

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。