RunProcessAsUser导致问题

时间:2014-08-25 13:21:18

标签: windows winapi windows-server-2008-r2 impersonation

当用户登录到他的帐户时,我有一个由服务自动启动的应用程序。有问题的应用程序是Winforms应用程序,问题是有时当应用程序从服务启动时,它会莫名其妙地挂起。杀死它并再次运行它没有服务工作正常。

我不确定为什么会发生这种情况以及为什么偶尔会发生这种情况(并不是所有时间)。我总是检查新的流程信息,它始终在登录用户的正确会话下运行。

我不确定在冒充用户时我是否做错了什么但是无论如何我列出的代码只是为了让某人可以找到它的缺陷:

public int RunWithTokenInSession(IntPtr token, int nSessionID)
{

    IntPtr primaryToken = GetUserTokenOfSessoin((uint)nSessionID);
    if (primaryToken == IntPtr.Zero)
    {
       return -1;
    }

    STARTUPINFO StartupInfo = new STARTUPINFO();
    processInfo_ = new PROCESS_INFORMATION();
    StartupInfo.cb = Marshal.SizeOf(StartupInfo);
    //StartupInfo.wShowWindow = (short)ShowCommands.SW_HIDE;
    StartupInfo.lpDesktop = "Winsta0\\Default";

    SECURITY_ATTRIBUTES Security1 = new SECURITY_ATTRIBUTES();
    SECURITY_ATTRIBUTES Security2 = new SECURITY_ATTRIBUTES();

    string command = "\"" + processPath_ + "\"";
    if ((arguments_ != null) && (arguments_.Length != 0))
    {
        command += " " + arguments_;
    }

    IntPtr lpEnvironment = IntPtr.Zero;
    bool resultEnv = CreateEnvironmentBlock(out lpEnvironment, primaryToken, false);
    if (resultEnv != true)
    {
        int nError = GetLastError();
    }

    bool b = CreateProcessAsUser(primaryToken, null, command, ref Security1, ref Security2, false, /*CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS |*/ CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS, lpEnvironment, null, ref StartupInfo, out processInfo_);
    int error = 0;
    if (!b)
    {
        error = Marshal.GetLastWin32Error();
        string message = String.Format("CreateProcessAsUser Error: {0}", error);
        Debug.WriteLine(message);
    }
    DestroyEnvironmentBlock(lpEnvironment);
    CloseHandle(primaryToken);

    return error;
}

这是GetUserTokenOfSessoin的代码:

public static IntPtr GetUserTokenOfSessoin(uint dwSessionId)
{
    IntPtr currentToken = IntPtr.Zero;
    IntPtr primaryToken = IntPtr.Zero;
    IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

    IntPtr hUserToken = IntPtr.Zero;
    IntPtr hTokenDup = IntPtr.Zero;


    bool bRet = WTSQueryUserToken(dwSessionId, out currentToken);
    if (bRet == false)
    {
        int n = GetLastError();
        return IntPtr.Zero;
    }


    bool fInAdminGroup = false;
    //IntPtr hToken = IntPtr.Zero;
    IntPtr hTokenToCheck = IntPtr.Zero;
    IntPtr pElevationType = IntPtr.Zero;
    IntPtr pLinkedToken = IntPtr.Zero;
    int cbSize = 0;


    if (Environment.OSVersion.Version.Major >= 6)
    {
        // Running Windows Vista or later (major version >= 6).
        // Determine token type: limited, elevated, or default.

        // Allocate a buffer for the elevation type information.
        cbSize = sizeof(TOKEN_ELEVATION_TYPE);
        pElevationType = Marshal.AllocHGlobal(cbSize);
        if (pElevationType == IntPtr.Zero)
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        // Retrieve token elevation type information.
        if (!GetTokenInformation(currentToken,
            TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
        TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(pElevationType);

        // If limited, get the linked elevated token for further check.
        if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
        {
            // Allocate a buffer for the linked token.
            cbSize = IntPtr.Size;
            pLinkedToken = Marshal.AllocHGlobal(cbSize);
            if (pLinkedToken == IntPtr.Zero)
            {
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            }

            // Get the linked token.
            if (!GetTokenInformation(currentToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, cbSize, out cbSize))
            {
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            }

            // Marshal the linked token value from native to .NET.
            hTokenToCheck = Marshal.ReadIntPtr(pLinkedToken);
            bRet = DuplicateTokenEx(hTokenToCheck, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);


        }
        else
        {
            bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
        }
    }
    else
    {
        // XP
        bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
    }

    if (bRet == false)
    {
        int lastError = Marshal.GetLastWin32Error();
        return IntPtr.Zero;
    }

    return primaryToken;
}

现在问题似乎只发生在Windows Server 2008 R2上,因为我还没有能够在任何其他版本的Windows上重现它,所以我想知道Server 2008是否有什么特别之处我是否需要采取额外的安全措施或获得额外的权限以用户身份运行该过程。

0 个答案:

没有答案