李sir_Blog

博客园 首页 联系 订阅 管理

/****************************** Module Header ******************************\
* Module Name:  CppRunAsUser.cpp
* Project:      CppRunAsUser
* Copyright (c) Microsoft Corporation.
*
*
*
* This source is subject to the Microsoft Public License.
* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
* All other rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/

#pragma region Includes and Manifest Dependencies
#include <stdio.h>
#include <windows.h>
#include <windowsx.h>
#include "Resource.h"

#include <userenv.h>
#pragma comment(lib, "userenv.lib")

// Enable Visual Style
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#pragma endregion


#pragma region Helper Functions

//
//   FUNCTION: ReportError(LPWSTR, DWORD)
//
//   PURPOSE: Display an error dialog for the failure of a certain function.
//
//   PARAMETERS:
//   * pszFunction - the name of the function that failed.
//   * dwError - the Win32 error code. Its default value is the calling
//   thread's last-error code value.
//
//   NOTE: The failing function must be immediately followed by the call of
//   ReportError if you do not explicitly specify the dwError parameter of
//   ReportError. This is to ensure that the calling thread's last-error code
//   value is not overwritten by any calls of API between the failing
//   function and ReportError.
//
void ReportError(LPWSTR pszFunction, DWORD dwError = GetLastError())
{
    wchar_t szMessage[200];
    int len = swprintf_s(szMessage, ARRAYSIZE(szMessage),
        L"%s failed w/err 0x%08lx", pszFunction, dwError);
    MessageBox(NULL, (len != -1) ? szMessage : pszFunction,
        L"An error occurred!", MB_ICONERROR);
}


//
//   FUNCTION: GetLogonSID(HANDLE, PSID *)
//
//   PURPOSE: Obtain the logon SID of the user.
//
//   PARAMETERS:
//   * hToken -
//   * ppSid -
//
BOOL GetLogonSID(HANDLE hToken, PSID *ppSid)
{
    BOOL fSucceeded = FALSE;
    DWORD cbTokenGroups = 0;
    PTOKEN_GROUPS pTokenGroups = NULL;
    DWORD dwIndex = 0;
    DWORD dwLength = 0;

    // Get required buffer size and allocate the TOKEN_GROUPS buffer.
    if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &cbTokenGroups))
    {
        if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
        {
            ReportError(L"GetTokenInformation");
            goto Exit;
        }

        pTokenGroups = (PTOKEN_GROUPS)LocalAlloc(LPTR, cbTokenGroups);
        if (pTokenGroups == NULL)
        {
            ReportError(L"LocalAlloc");
            goto Exit;
        }
    }

    // Get the token group information from the access token.
    if (!GetTokenInformation(hToken, TokenGroups, pTokenGroups,
        cbTokenGroups, &cbTokenGroups))
    {
        ReportError(L"GetTokenInformation");
        goto Exit;
    }

    // Loop through the groups to find the logon SID.
    for (dwIndex = 0; dwIndex < pTokenGroups->GroupCount; dwIndex++)
    {
        if ((pTokenGroups->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
            ==  SE_GROUP_LOGON_ID)
        {
            // Found the logon SID; make a copy of it.

            // Determine the length of the SID.
            dwLength = GetLengthSid(pTokenGroups->Groups[dwIndex].Sid);

            // Allocate a buffer for the logon SID.
            *ppSid = (PSID)LocalAlloc(LPTR, dwLength);
            if (*ppSid == NULL)
            {
                ReportError(L"LocalAlloc");
                goto Exit;
            }

            // Obtain a copy of the logon SID.
            if (!CopySid(dwLength, *ppSid, pTokenGroups->Groups[dwIndex].Sid))
            {
                ReportError(L"CopySid");
                goto Exit;
            }

            break;
        }
    }

    fSucceeded = TRUE;

Exit:

    // Centralized cleanup for all allocated resources. Clean up only those
    // which were allocated, and clean them up in the right order.

    if (pTokenGroups)
    {
        if (LocalFree(pTokenGroups))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        // Set variable to same state as resources
        pTokenGroups = NULL;
        cbTokenGroups = 0;
    }

    return fSucceeded;
}


//
//   FUNCTION: FreeLogonSID(PSID *)
//
//   PURPOSE: Free the logon SID of the user.
//
//   PARAMETERS:
//   * pSid -
//
void FreeLogonSID(PSID *ppSid)
{
    if (LocalFree(*ppSid))
    {
        ReportError(L"LocalFree");
    }
}


#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | \
    GENERIC_ALL)

#define WINSTA_ALL (WINSTA_ACCESSCLIPBOARD  | WINSTA_ACCESSGLOBALATOMS | \
   WINSTA_CREATEDESKTOP    | WINSTA_ENUMDESKTOPS      | \
   WINSTA_ENUMERATE        | WINSTA_EXITWINDOWS       | \
   WINSTA_READATTRIBUTES   | WINSTA_READSCREEN        | \
   WINSTA_WRITEATTRIBUTES  | DELETE                   | \
   READ_CONTROL            | WRITE_DAC                | \
   WRITE_OWNER)

#define DESKTOP_ALL (DESKTOP_CREATEMENU      | DESKTOP_CREATEWINDOW  | \
   DESKTOP_ENUMERATE       | DESKTOP_HOOKCONTROL   | \
   DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | \
   DESKTOP_READOBJECTS     | DESKTOP_SWITCHDESKTOP | \
   DESKTOP_WRITEOBJECTS    | DELETE                | \
   READ_CONTROL            | WRITE_DAC             | \
   WRITE_OWNER)


BOOL AddAceToWindowStation(HWINSTA hWinsta, PSID pSid)
{
    BOOL fSucceeded = FALSE;
    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;

    DWORD cbSd = 0;
    PSECURITY_DESCRIPTOR pSd = NULL;
    BOOL fDaclPresent = FALSE;
    BOOL fDaclExist = FALSE;
    ACL_SIZE_INFORMATION aclSizeInfo = { 0 };
    DWORD cbDacl = 0;
    PACL pDacl = NULL;

    PSECURITY_DESCRIPTOR pNewSd = NULL;
    DWORD cbNewDacl = 0;
    PACL pNewDacl = NULL;
    DWORD cbNewAce = 0;
    PACCESS_ALLOWED_ACE pNewAce = NULL;

    DWORD dwIndex = 0;
    PVOID pTempAce = NULL;

    // Get required buffer size and allocate the SECURITY_DESCRIPTOR buffer.
    if (!GetUserObjectSecurity(hWinsta, &si, NULL, 0, &cbSd))
    {
        if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
        {
            ReportError(L"GetUserObjectSecurity");
            goto Exit;
        }

        pSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSd);
        if (pSd == NULL)
        {
            ReportError(L"LocalAlloc");
            goto Exit;
        }
    }

    // Obtain the security descriptor for the window station.
    if (!GetUserObjectSecurity(hWinsta, &si, pSd, cbSd, &cbSd))
    {
        ReportError(L"GetUserObjectSecurity");
        goto Exit;
    }

    // Get the DACL from the security descriptor.
    if (!GetSecurityDescriptorDacl(pSd, &fDaclPresent, &pDacl, &fDaclExist))
    {
        ReportError(L"GetSecurityDescriptorDacl");
        goto Exit;
    }

    // Get the size information of the DACL.
    if (pDacl == NULL)
    {
        // If GetSecurityDescriptorDacl stores a NULL value in the pointer
        // pointed to by pDacl, the security descriptor has a NULL DACL. A
        // NULL DACL implicitly allows all access to an object.
        cbDacl = 0;
    }
    else
    {
        if (!GetAclInformation(pDacl, (LPVOID)&aclSizeInfo,
            sizeof(aclSizeInfo), AclSizeInformation))
        {
            ReportError(L"GetAclInformation");
            goto Exit;
        }
        cbDacl = aclSizeInfo.AclBytesInUse;
    }

    // Allocate memory for the new security descriptor.
    pNewSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSd);
    if (pNewSd == NULL)
    {
        ReportError(L"LocalAlloc");
        goto Exit;
    }

    // Initialize the new security descriptor.
    if (!InitializeSecurityDescriptor(pNewSd, SECURITY_DESCRIPTOR_REVISION))
    {
        ReportError(L"InitializeSecurityDescriptor");
        goto Exit;
    }

    // Compute the size of a DACL to be added to the new security descriptor.
    cbNewAce = sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
    cbNewDacl = (cbDacl == 0 ? sizeof(ACL) : cbDacl) + 2 * cbNewAce;

    // Allocate memory for the new DACL.
    pNewDacl = (PACL)LocalAlloc(LPTR, cbNewDacl);
    if (pNewDacl == NULL)
    {
        ReportError(L"LocalAlloc");
        goto Exit;
    }

    // Initialize the new DACL.
    if (!InitializeAcl(pNewDacl, cbNewDacl, ACL_REVISION))
    {
        ReportError(L"InitializeAcl");
        goto Exit;
    }

    // If the original DACL is present, copy it to the new DACL.
    if (fDaclPresent)
    {
        // Copy the ACEs to the new DACL.
        if (aclSizeInfo.AceCount)
        {
            for (dwIndex = 0; dwIndex < aclSizeInfo.AceCount; dwIndex++)
            {
                // Get an ACE.
                if (!GetAce(pDacl, dwIndex, &pTempAce))
                {
                    ReportError(L"GetAce");
                    goto Exit;
                }

                // Add the ACE to the new ACL.
                if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pTempAce,
                    ((PACE_HEADER)pTempAce)->AceSize))
                {
                    ReportError(L"AddAce");
                    goto Exit;
                }
            }
        }
    }

    // Add two new ACEs to the new DACL to allow the SID full access to the
    // interactive window station.

    pNewAce = (PACCESS_ALLOWED_ACE)LocalAlloc(LPTR, cbNewAce);
    if (pNewAce == NULL)
    {
        ReportError(L"LocalAlloc");
        goto Exit;
    }

    pNewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
    pNewAce->Header.AceFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE |
        OBJECT_INHERIT_ACE;
    pNewAce->Header.AceSize = (WORD)cbNewAce;
    pNewAce->Mask = GENERIC_ACCESS;
    if (!CopySid(GetLengthSid(pSid), &pNewAce->SidStart, pSid))
    {
        ReportError(L"CopySid");
        goto Exit;
    }

    if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, (LPVOID)pNewAce,
        pNewAce->Header.AceSize))
    {
        ReportError(L"AddAce");
        goto Exit;
    }

    pNewAce->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
    pNewAce->Mask = WINSTA_ALL;

    if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, (LPVOID)pNewAce,
        pNewAce->Header.AceSize))
    {
        ReportError(L"AddAce");
        goto Exit;
    }

    // Assign the new DACL to the new security descriptor.
    if (!SetSecurityDescriptorDacl(pNewSd, TRUE, pNewDacl, FALSE))
    {
        ReportError(L"SetSecurityDescriptorDacl");
        goto Exit;
    }

    // Set the new security descriptor for the window station.
    if (!SetUserObjectSecurity(hWinsta, &si, pNewSd))
    {
        ReportError(L"SetUserObjectSecurity");
        goto Exit;
    }

    fSucceeded = TRUE;

Exit:

    // Centralized cleanup for all allocated resources. Clean up only those
    // which were allocated, and clean them up in the right order.

    if (pSd)
    {
        if (LocalFree(pSd))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pSd = NULL;
        cbSd = 0;
    }

    if (pNewSd)
    {
        if (LocalFree(pNewSd))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pNewSd = NULL;
    }

    if (pNewDacl)
    {
        if (LocalFree(pNewDacl))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pNewDacl = NULL;
        cbNewDacl = 0;
    }

    if (pNewAce)
    {
        if (LocalFree(pNewAce))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pNewAce = NULL;
        cbNewAce = 0;
    }

    return fSucceeded;
}


BOOL AddAceToDesktop(HDESK hDesktop, PSID pSid)
{
    BOOL fSucceeded = FALSE;
    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;

    DWORD cbSd = 0;
    PSECURITY_DESCRIPTOR pSd = NULL;
    BOOL fDaclPresent = FALSE;
    BOOL fDaclExist = FALSE;
    ACL_SIZE_INFORMATION aclSizeInfo = { 0 };
    DWORD cbDacl = 0;
    PACL pDacl = NULL;

    PSECURITY_DESCRIPTOR pNewSd = NULL;
    DWORD cbNewDacl = 0;
    PACL pNewDacl = NULL;
    DWORD cbNewAce = 0;
    PACCESS_ALLOWED_ACE pNewAce = NULL;

    DWORD dwIndex = 0;
    PVOID pTempAce = NULL;

    // Get required buffer size and allocate the SECURITY_DESCRIPTOR buffer.
    if (!GetUserObjectSecurity(hDesktop, &si, NULL, 0, &cbSd))
    {
        if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
        {
            ReportError(L"GetUserObjectSecurity");
            goto Exit;
        }

        pSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSd);
        if (pSd == NULL)
        {
            ReportError(L"LocalAlloc");
            goto Exit;
        }
    }

    // Obtain the security descriptor for the desktop object.
    if (!GetUserObjectSecurity(hDesktop, &si, pSd, cbSd, &cbSd))
    {
        ReportError(L"GetUserObjectSecurity");
        goto Exit;
    }

    // Get the DACL from the security descriptor.
    if (!GetSecurityDescriptorDacl(pSd, &fDaclPresent, &pDacl, &fDaclExist))
    {
        ReportError(L"GetSecurityDescriptorDacl");
        goto Exit;
    }

    // Get the size information of the DACL.
    if (pDacl == NULL)
    {
        cbDacl = 0;
    }
    else
    {
        if (!GetAclInformation(pDacl, (LPVOID)&aclSizeInfo,
            sizeof(aclSizeInfo), AclSizeInformation))
        {
            ReportError(L"GetAclInformation");
            goto Exit;
        }
        cbDacl = aclSizeInfo.AclBytesInUse;
    }

    // Allocate memory for the new security descriptor.
    pNewSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSd);
    if (pNewSd == NULL)
    {
        ReportError(L"LocalAlloc");
        goto Exit;
    }

    // Initialize the new security descriptor.
    if (!InitializeSecurityDescriptor(pNewSd, SECURITY_DESCRIPTOR_REVISION))
    {
        ReportError(L"InitializeSecurityDescriptor");
        goto Exit;
    }

    // Compute the size of a DACL to be added to the new security descriptor.
    cbNewAce = sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
    cbNewDacl = (cbDacl == 0 ? sizeof(ACL) : cbDacl) + cbNewAce;

    // Allocate memory for the new DACL.
    pNewDacl = (PACL)LocalAlloc(LPTR, cbNewDacl);
    if (pNewDacl == NULL)
    {
        ReportError(L"LocalAlloc");
        goto Exit;
    }

    // Initialize the new DACL.
    if (!InitializeAcl(pNewDacl, cbNewDacl, ACL_REVISION))
    {
        ReportError(L"InitializeAcl");
        goto Exit;
    }

    // If the original DACL is present, copy it to the new DACL.
    if (fDaclPresent)
    {
        // Copy the ACEs to the new DACL.
        if (aclSizeInfo.AceCount)
        {
            for (dwIndex = 0; dwIndex < aclSizeInfo.AceCount; dwIndex++)
            {
                // Get an ACE.
                if (!GetAce(pDacl, dwIndex, &pTempAce))
                {
                    ReportError(L"GetAce");
                    goto Exit;
                }

                // Add the ACE to the new ACL.
                if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pTempAce,
                    ((PACE_HEADER)pTempAce)->AceSize))
                {
                    ReportError(L"AddAce");
                    goto Exit;
                }
            }
        }
    }

    // Add a new ACE to the new DACL.
    if (!AddAccessAllowedAce(pNewDacl, ACL_REVISION, DESKTOP_ALL, pSid))
    {
        ReportError(L"AddAccessAllowedAce");
        goto Exit;
    }

    // Assign the new DACL to the new security descriptor.
    if (!SetSecurityDescriptorDacl(pNewSd, TRUE, pNewDacl, FALSE))
    {
        ReportError(L"SetSecurityDescriptorDacl");
        goto Exit;
    }

    //  Set the new security descriptor for the desktop object.
    if (!SetUserObjectSecurity(hDesktop, &si, pNewSd))
    {
        ReportError(L"SetUserObjectSecurity");
        goto Exit;
    }

    fSucceeded = TRUE;

Exit:

    // Centralized cleanup for all allocated resources. Clean up only those
    // which were allocated, and clean them up in the right order.

    if (pSd)
    {
        if (LocalFree(pSd))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pSd = NULL;
        cbSd = 0;
    }

    if (pNewSd)
    {
        if (LocalFree(pNewSd))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pNewSd = NULL;
    }

    if (pNewDacl)
    {
        if (LocalFree(pNewDacl))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pNewDacl = NULL;
        cbNewDacl = 0;
    }

    if (pNewAce)
    {
        if (LocalFree(pNewAce))
        {
            fSucceeded = FALSE;
            ReportError(L"LocalFree");
        }
        pNewAce = NULL;
        cbNewAce = 0;
    }

    return fSucceeded;
}

#pragma endregion


#pragma region CreateInteractiveProcessWithLogon

//
//   FUNCTION: CreateInteractiveProcessWithLogon(LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR)
//
//   PURPOSE:
//
//   PARAMETERS:
//   * pszUserName - A pointer to a null-terminated string that specifies the
//   name of the user. This is the name of the user account to log on to. If
//   you use the user principal name (UPN) format, User@DNSDomainName, the
//   pszDomain parameter must be NULL.
//   * pszDomain - A pointer to a null-terminated string that specifies the
//   name of the domain or server whose account database contains the
//   pszUsername account. If this parameter is NULL, the user name must be
//   specified in UPN format. If this parameter is ".", the function validates
//   the account by using only the local account database.
//   * pszPassword - A pointer to a null-terminated string that specifies the
//   plaintext password for the user account specified by lpszUsername. When
//   you have finished using the password, clear the password from memory by
//   calling the SecureZeroMemory function.
//   * pszCommandLine - The command line to be executed. The maximum length
//   of this string is 1024 characters. The module name portion of
//   pszCommandLine is limited to MAX_PATH characters.
//
//   NOTE:
//
BOOL CreateInteractiveProcessWithLogon(LPCWSTR pszUserName,
                                       LPCWSTR pszDomain,
                                       LPCWSTR pszPassword,
                                       LPWSTR pszCommandLine)
{
    BOOL fSucceeded = FALSE;
    HANDLE hToken = NULL;
    LPVOID lpvEnv = NULL;
    wchar_t szUserProfile[MAX_PATH];
    DWORD dwSize = 0;
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };

    // Attempt to log the user on to the local computer. The logon type is
    // intended for users who will be interactively using the computer.
    if (!LogonUser(pszUserName, pszDomain, pszPassword,
        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
    {
        ReportError(L"LogonUser");
        goto Exit;
    }

    // Retrieve the environment variables for the specified user. The
    // environment block inherits from the current process's environment.
    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
    {
        ReportError(L"CreateEnvironmentBlock");
        goto Exit;
    }

    // Retrieve the path to the root directory of the user's profile.
    dwSize = ARRAYSIZE(szUserProfile);
    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
    {
        ReportError(L"GetUserProfileDirectory");
        goto Exit;
    }

    // If the lpDesktop member of the STARTUPINFO structure is initialized
    // to either NULL or "", CreateProcessWithLogonW implementation adds
    // permissions for the specified user account to the window station and
    // desktop inherited from the parent process, which is "winsta0\default"
    // for the "Default" application desktop.
    si.lpDesktop = NULL;

    // Launch the interative child process.
    if (!CreateProcessWithLogonW(pszUserName, pszDomain, pszPassword,
        LOGON_WITH_PROFILE, NULL, pszCommandLine,
        CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, &si, &pi))
    {
        ReportError(L"CreateProcessWithLogonW");
        goto Exit;
    }

    // The child process is running now ...

    // (Optional) Wait for the exit of the child process.
    //WaitForSingleObject(pi.hProcess);

    fSucceeded = TRUE;

Exit:

    // Centralized cleanup for all allocated resources. Clean up only those
    // which were allocated, and clean them up in the right order.

    if (hToken)
    {
        if (!CloseHandle(hToken))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        hToken = NULL;
    }

    if (lpvEnv)
    {
        if (!DestroyEnvironmentBlock(lpvEnv))
        {
            fSucceeded = FALSE;
            ReportError(L"DestroyEnvironmentBlock");
        }
        lpvEnv = NULL;
    }

    if (pi.hProcess)
    {
        if (!CloseHandle(pi.hProcess))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        pi.hProcess = NULL;
    }

    if (pi.hThread)
    {
        if (!CloseHandle(pi.hThread))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        pi.hThread = NULL;
    }

    return fSucceeded;
}

#pragma endregion


#pragma region CreateInteractiveProcessWithToken

//
//   FUNCTION: CreateInteractiveProcessWithToken(LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR)
//
//   PURPOSE:
//
//   PARAMETERS:
//   * pszUserName - A pointer to a null-terminated string that specifies the
//   name of the user. This is the name of the user account to log on to. If
//   you use the user principal name (UPN) format, User@DNSDomainName, the
//   pszDomain parameter must be NULL.
//   * pszDomain - A pointer to a null-terminated string that specifies the
//   name of the domain or server whose account database contains the
//   pszUsername account. If this parameter is NULL, the user name must be
//   specified in UPN format. If this parameter is ".", the function validates
//   the account by using only the local account database.
//   * pszPassword - A pointer to a null-terminated string that specifies the
//   plaintext password for the user account specified by lpszUsername. When
//   you have finished using the password, clear the password from memory by
//   calling the SecureZeroMemory function.
//   * pszCommandLine - The command line to be executed. The maximum length
//   of this string is 1024 characters. The module name portion of
//   pszCommandLine is limited to MAX_PATH characters.
//
//   NOTE:
//
BOOL CreateInteractiveProcessWithToken(LPCWSTR pszUserName,
                                       LPCWSTR pszDomain,
                                       LPCWSTR pszPassword,
                                       LPWSTR pszCommandLine)
{
    BOOL fSucceeded = FALSE;
    HANDLE hToken = NULL;
    HWINSTA hWinstaSave = NULL;
    HWINSTA hWinsta = NULL;
    HDESK hDesktop = NULL;
    PSID pSid = NULL;
    wchar_t szUserProfile[MAX_PATH];
    DWORD dwSize = ARRAYSIZE(szUserProfile);
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };

    // Attempt to log the user on to the local computer. The logon type is
    // intended for users who will be interactively using the computer.
    if (!LogonUser(pszUserName, pszDomain, pszPassword,
        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
    {
        ReportError(L"LogonUser");
        goto Exit;
    }

    // Save a handle to the caller's current window station.
    hWinstaSave = GetProcessWindowStation();
    if (hWinstaSave == NULL)
    {
        ReportError(L"GetProcessWindowStation");
        goto Exit;
    }

    // Get a handle to the interactive window station.
    hWinsta = OpenWindowStation(
        L"winsta0",                  // The interactive window station
        FALSE,                       // Handle is not inheritable
        READ_CONTROL | WRITE_DAC);   // Rights to read/write the DACL
    if (hWinsta == NULL)
    {
        ReportError(L"OpenWindowStation");
        goto Exit;
    }

    // To get the correct default desktop, set the caller's window station
    // to the interactive window station.
    if (!SetProcessWindowStation(hWinsta))
    {
        ReportError(L"SetProcessWindowStation");
        goto Exit;
    }

    // Get a handle to the interactive desktop.
    hDesktop = OpenDesktop(
        L"default",            // The interactive window station
        0,                     // No interaction with other desktop processes
        FALSE,                 // Handle is not inheritable
        READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS |
        DESKTOP_READOBJECTS);  // Rights to read/write the DACL

    // Restore the caller's window station.
    if (!SetProcessWindowStation(hWinstaSave))
    {
        ReportError(L"SetProcessWindowStation");
        goto Exit;
    }

    if (hDesktop == NULL)
    {
        ReportError(L"OpenDesktop");
        goto Exit;
    }

    // Get the SID for the client's logon session.
    if (!GetLogonSID(hToken, &pSid))
    {
        goto Exit;
    }

    // Allow logon SID full access to interactive window station.
    if (!AddAceToWindowStation(hWinsta, pSid))
    {
        goto Exit;
    }

    // Allow logon SID full access to interactive desktop.
    if (!AddAceToDesktop(hDesktop, pSid))
    {
        goto Exit;
    }

    // Retrieve the path to the root directory of the user's profile.
    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
    {
        ReportError(L"GetUserProfileDirectory");
        goto Exit;
    }

    // Specify that the child process runs in the interactive desktop.
    si.lpDesktop = L"winsta0\\default";

    // Launch the process in the client's logon session.
    if (!CreateProcessWithTokenW(hToken, LOGON_WITH_PROFILE, NULL,
        pszCommandLine, CREATE_UNICODE_ENVIRONMENT, NULL, szUserProfile,
        &si, &pi))
    {
        ReportError(L"CreateProcessWithTokenW");
        goto Exit;
    }

    // The child process is running now ...

    // (Optional) Wait for the exit of the child process.
    //WaitForSingleObject(pi.hProcess);

    fSucceeded = TRUE;

Exit:

    // Centralized cleanup for all allocated resources. Clean up only those
    // which were allocated, and clean them up in the right order.

    if (hToken)
    {
        if (!CloseHandle(hToken))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        hToken = NULL;
    }

    if (hWinsta)
    {
        if (!CloseWindowStation(hWinsta))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseWindowStation");
        }
        hWinsta = NULL;
    }

    if (hDesktop)
    {
        if (!CloseDesktop(hDesktop))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseDesktop");
        }
        hDesktop = NULL;
    }

    if (pSid)
    {
        FreeLogonSID(&pSid);
        pSid = NULL;
    }

    if (pi.hProcess)
    {
        if (!CloseHandle(pi.hProcess))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        pi.hProcess = NULL;
    }

    if (pi.hThread)
    {
        if (!CloseHandle(pi.hThread))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        pi.hThread = NULL;
    }

    return fSucceeded;
}

#pragma endregion


#pragma region CreateInteractiveProcessAsUser


//
//   FUNCTION: CreateInteractiveProcessAsUser(LPCWSTR, LPCWSTR, LPCWSTR, LPWSTR)
//
//   PURPOSE:
//
//   PARAMETERS:
//   * pszUserName - A pointer to a null-terminated string that specifies the
//   name of the user. This is the name of the user account to log on to. If
//   you use the user principal name (UPN) format, User@DNSDomainName, the
//   pszDomain parameter must be NULL.
//   * pszDomain - A pointer to a null-terminated string that specifies the
//   name of the domain or server whose account database contains the
//   pszUsername account. If this parameter is NULL, the user name must be
//   specified in UPN format. If this parameter is ".", the function validates
//   the account by using only the local account database.
//   * pszPassword - A pointer to a null-terminated string that specifies the
//   plaintext password for the user account specified by lpszUsername. When
//   you have finished using the password, clear the password from memory by
//   calling the SecureZeroMemory function.
//   * pszCommandLine - The command line to be executed. The maximum length
//   of this string is 1024 characters. The module name portion of
//   pszCommandLine is limited to MAX_PATH characters.
//
//   NOTE:
//
BOOL CreateInteractiveProcessAsUser(LPCWSTR pszUserName,
                                    LPCWSTR pszDomain,
                                    LPCWSTR pszPassword,
                                    LPWSTR pszCommandLine)
{
    BOOL fSucceeded = FALSE;
    HANDLE hToken = NULL;
    HWINSTA hWinstaSave = NULL;
    HWINSTA hWinsta = NULL;
    HDESK hDesktop = NULL;
    PSID pSid = NULL;
    wchar_t szUserProfile[MAX_PATH];
    DWORD dwSize = ARRAYSIZE(szUserProfile);
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };

    // Attempt to log the user on to the local computer. The logon type is
    // intended for users who will be interactively using the computer.
    if (!LogonUser(pszUserName, pszDomain, pszPassword,
        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
    {
        ReportError(L"LogonUser");
        goto Exit;
    }

    // Save a handle to the caller's current window station.
    hWinstaSave = GetProcessWindowStation();
    if (hWinstaSave == NULL)
    {
        ReportError(L"GetProcessWindowStation");
        goto Exit;
    }

    // Get a handle to the interactive window station.
    hWinsta = OpenWindowStation(
        L"winsta0",                  // The interactive window station
        FALSE,                       // Handle is not inheritable
        READ_CONTROL | WRITE_DAC);   // Rights to read/write the DACL
    if (hWinsta == NULL)
    {
        ReportError(L"OpenWindowStation");
        goto Exit;
    }

    // To get the correct default desktop, set the caller's window station
    // to the interactive window station.
    if (!SetProcessWindowStation(hWinsta))
    {
        ReportError(L"SetProcessWindowStation");
        goto Exit;
    }

    // Get a handle to the interactive desktop.
    hDesktop = OpenDesktop(
        L"default",            // The interactive window station
        0,                     // No interaction with other desktop processes
        FALSE,                 // Handle is not inheritable
        READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS |
        DESKTOP_READOBJECTS);  // Rights to read/write the DACL

    // Restore the caller's window station.
    if (!SetProcessWindowStation(hWinstaSave))
    {
        ReportError(L"SetProcessWindowStation");
        goto Exit;
    }

    if (hDesktop == NULL)
    {
        ReportError(L"OpenDesktop");
        goto Exit;
    }

    // Get the SID for the client's logon session.
    if (!GetLogonSID(hToken, &pSid))
    {
        goto Exit;
    }

    // Allow logon SID full access to interactive window station.
    if (!AddAceToWindowStation(hWinsta, pSid))
    {
        goto Exit;
    }

    // Allow logon SID full access to interactive desktop.
    if (!AddAceToDesktop(hDesktop, pSid))
    {
        goto Exit;
    }

    // Retrieve the path to the root directory of the user's profile.
    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
    {
        ReportError(L"GetUserProfileDirectory");
        goto Exit;
    }

    // Specify that the child process runs in the interactive desktop.
    si.lpDesktop = L"winsta0\\default";

    // Launch the process in the client's logon session. The process that
    // calls the CreateProcessAsUser function must have the
    // SE_ASSIGNPRIMARYTOKEN_NAME and SE_INCREASE_QUOTA_NAME privileges.
    // Generally only processes run as the SYSTEM account has both
    // privileges. The function fails with the ERROR_PRIVILEGE_NOT_HELD
    // (0x522) error when the required privileges are not available.
    if (!CreateProcessAsUser(hToken, NULL, pszCommandLine, NULL, NULL, FALSE,
        CREATE_UNICODE_ENVIRONMENT, NULL, szUserProfile, &si, &pi))
    {
        ReportError(L"CreateProcessAsUser");
        goto Exit;
    }

    // The child process is running now ...

    // (Optional) Wait for the exit of the child process.
    //WaitForSingleObject(pi.hProcess);

    fSucceeded = TRUE;

Exit:

    // Centralized cleanup for all allocated resources. Clean up only those
    // which were allocated, and clean them up in the right order.

    if (hToken)
    {
        if (!CloseHandle(hToken))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        hToken = NULL;
    }

    if (hWinsta)
    {
        if (!CloseWindowStation(hWinsta))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseWindowStation");
        }
        hWinsta = NULL;
    }

    if (hDesktop)
    {
        if (!CloseDesktop(hDesktop))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseDesktop");
        }
        hDesktop = NULL;
    }

    if (pSid)
    {
        FreeLogonSID(&pSid);
        pSid = NULL;
    }

    if (pi.hProcess)
    {
        if (!CloseHandle(pi.hProcess))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        pi.hProcess = NULL;
    }

    if (pi.hThread)
    {
        if (!CloseHandle(pi.hThread))
        {
            fSucceeded = FALSE;
            ReportError(L"CloseHandle");
        }
        pi.hThread = NULL;
    }

    return fSucceeded;
}

#pragma endregion


void OnCreateProcess(HWND hWnd, int id)
{
    int cchText;
    DWORD cbUserName = 0;
    PWSTR pszUserName = NULL;
    DWORD cbDomain = 0;
    PWSTR pszDomain = NULL;
    DWORD cbPassword = 0;
    PWSTR pszPassword = NULL;
    DWORD cbCommand = 0;
    PWSTR pszCommand = NULL;

    // Get the user name from the dialog.
    HWND hUserNameEdit = GetDlgItem(hWnd, IDC_USERNAME_EDIT);
    cchText = GetWindowTextLength(hUserNameEdit);
    if (cchText == 0)
    {
        MessageBox(hWnd, L"User Name cannot be empty", L"Error", MB_ICONERROR);
        goto Exit;
    }
    cbUserName = (cchText + 1) * sizeof(*pszUserName);
    pszUserName = (PWSTR)LocalAlloc(LPTR, cbUserName);
    GetWindowText(hUserNameEdit, pszUserName, cchText + 1);

    // Get the domain from the dialog.
    HWND hDomainEdit = GetDlgItem(hWnd, IDC_DOMAIN_EDIT);
    cchText = GetWindowTextLength(hDomainEdit);
    if (cchText != 0)
    {
        cbDomain = (cchText + 1) * sizeof(*pszDomain);
        pszDomain = (PWSTR)LocalAlloc(LPTR, cbDomain);
        GetWindowText(hDomainEdit, pszDomain, cchText + 1);
    }

    // Get the password from the dialog.
    HWND hPasswordEdit = GetDlgItem(hWnd, IDC_PASSWORD_EDIT);
    cchText = GetWindowTextLength(hPasswordEdit);
    if (cchText != 0)
    {
        cbPassword = (cchText + 1) * sizeof(*pszPassword);
        pszPassword = (PWSTR)LocalAlloc(LPTR, cbPassword);
        GetWindowText(hPasswordEdit, pszPassword, cchText + 1);
    }

    // Get the command from the dialog.
    HWND hCommandEdit = GetDlgItem(hWnd, IDC_COMMAND_EDIT);
    cchText = GetWindowTextLength(hCommandEdit);
    if (cchText == 0)
    {
        MessageBox(hWnd, L"Command cannot be empty", L"Error", MB_ICONERROR);
        goto Exit;
    }
    cbCommand = (cchText + 1) * sizeof(*pszCommand);
    pszCommand = (PWSTR)LocalAlloc(LPTR, cbCommand);
    GetWindowText(hCommandEdit, pszCommand, cchText + 1);

    // Create the child process.

    switch (id)
    {
    case IDC_CREATEPROCESSWITHLOGON_BN:
        if (!CreateInteractiveProcessWithLogon(pszUserName, pszDomain,
            pszPassword, pszCommand))
        {
            ReportError(L"CreateInteractiveProcessWithLogon");
        }
        break;

    case IDC_CREATEPROCESSWITHTOKEN_BN:
        if (!CreateInteractiveProcessWithToken(pszUserName, pszDomain,
            pszPassword, pszCommand))
        {
            ReportError(L"CreateInteractiveProcessWithToken");
        }
        break;

    case IDC_CREATEPROCESSASUSER_BN:
        if (!CreateInteractiveProcessAsUser(pszUserName, pszDomain,
            pszPassword, pszCommand))
        {
            ReportError(L"CreateInteractiveProcessAsUser");
        }
        break;
    }

Exit:

    if (pszUserName)
    {
        if (LocalFree(pszUserName))
        {
            ReportError(L"LocalFree");
        }
        pszUserName = NULL;
        cbUserName = 0;
    }

    if (pszDomain)
    {
        if (LocalFree(pszDomain))
        {
            ReportError(L"LocalFree");
        }
        pszDomain = NULL;
        cbDomain = 0;
    }

    if (pszPassword)
    {
        SecureZeroMemory(pszPassword, cbPassword);
        if (LocalFree(pszPassword))
        {
            ReportError(L"LocalFree");
        }
        pszPassword = NULL;
        cbPassword = 0;
    }

    if (pszCommand)
    {
        if (LocalFree(pszCommand))
        {
            ReportError(L"LocalFree");
        }
        pszCommand = NULL;
        cbCommand = 0;
    }
}


//
//   FUNCTION: OnInitDialog(HWND, HWND, LPARAM)
//
//   PURPOSE: Process the WM_INITDIALOG message.
//
BOOL OnInitDialog(HWND hWnd, HWND hwndFocus, LPARAM lParam)
{
    return TRUE;
}


//
//   FUNCTION: OnCommand(HWND, int, HWND, UINT)
//
//   PURPOSE: Process the WM_COMMAND message.
//
void OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify)
{
    switch (id)
    {
    case IDC_CREATEPROCESSWITHLOGON_BN:
    case IDC_CREATEPROCESSWITHTOKEN_BN:
    case IDC_CREATEPROCESSASUSER_BN:
        OnCreateProcess(hWnd, id);
        break;
    case IDOK:
    case IDCANCEL:
        EndDialog(hWnd, 0);
        break;
    }
}


//
//   FUNCTION: OnClose(HWND)
//
//   PURPOSE: Process the WM_CLOSE message.
//
void OnClose(HWND hWnd)
{
    EndDialog(hWnd, 0);
}


//
//  FUNCTION: DialogProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main dialog.
//
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        // Handle the WM_INITDIALOG message in OnInitDialog
        HANDLE_MSG (hWnd, WM_INITDIALOG, OnInitDialog);

        // Handle the WM_COMMAND message in OnCommand
        HANDLE_MSG (hWnd, WM_COMMAND, OnCommand);

        // Handle the WM_CLOSE message in OnClose
        HANDLE_MSG (hWnd, WM_CLOSE, OnClose);

    default:
        return FALSE;
    }
    return 0;
}


//
//  FUNCTION: wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
//
//  PURPOSE:  The entry point of the application.
//
int APIENTRY wWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPWSTR    lpCmdLine,
                      int       nCmdShow)
{
    return DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, DialogProc);
}

posted on 2010-12-01 17:37  李sir  阅读(1180)  评论(0编辑  收藏  举报