通过CreateProcessAsUser从Web服务使用委派创建的连续进程无法读/写网络共享

时间:2012-05-29 22:08:20

标签: rest iis-7 pinvoke impersonation createprocessasuser

什么可能导致通过CreateProcessAsUser从Web服务创建的连续进程使用委派在尝试访问网络共享时遇到System.UnauthorizedAccessException异常?

WCF Rest Web服务使用带有重复用户令牌的CreateProcessAsUser启动新进程。该过程启动并报告它由拥有该共享访问权限的模拟用户拥有。

在Web服务器的干净启动时,进程可以在网络共享目录(\\ nasshare \ test)上反复调用System.IO.Directory.Exists并获得正确的响应。但是,当进程结束并再次调用Web服务再次启动进程时,它将报告该目录不再存在,然后我的程序代码尝试创建所谓的缺失目录并失败,并显示异常消息:System。 UnauthorizedAccessException:拒绝访问路径'\\ nasshare \ test'。

奇怪的是,如果我重新启动网络服务器,它将再次运行......直到流程结束。 Web服务创建的连续进程将失败。当我从Web服务器上的命令提示符运行该进程时,进程可以看到该文件夹​​并写入该文件夹。我可以通过这种方式反复运行该过程,并且在使用Web服务器中的CreateProcessAsUser启动失败后,它甚至会立即正常工作。

  • Web服务器:Windows Server 2008 R2
  • 网络共享:Windows Storage Server 2003
  • 网络服务托管:IIS7
  • 网络服务客户端:IE,Chrome
  • 应用程序池标识:NetworkService
  • .Net Framework:v4.0

Simplified Rest Web服务

[Description("Launch a process.")]
[WebGet(UriTemplate = "fragment/launch")]
public void LaunchProcess()
{
    ...
    using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
    {
        launchProcessAs(WindowsIdentity.GetCurrent().Token, @"c:\temp\test.exe", "1234"); //In this test the arg "1234" is not used
    }
}//end rest func call

const UInt32 MAXIMUM_ALLOWED = 0x2000000;
const UInt32 GENERIC_ALL_ACCESS = 0x10000000;
const Int32 CREATE_NEW_PROCESS_GROUP = 0x00000200;
const Int32 CREATE_UNICODE_ENVIRONMENT = 0x00000400;
const Int32 IDLE_PRIORITY_CLASS = 0x40;
const Int32 NORMAL_PRIORITY_CLASS = 0x20;
const Int32 HIGH_PRIORITY_CLASS = 0x80;
const Int32 REALTIME_PRIORITY_CLASS = 0x100;
const Int32 CREATE_NEW_CONSOLE = 0x00000010;
const Int32 DETACHED_PROCESS = 0x00000008;

public bool launchProcessAs(IntPtr userToken, string pathToProcess, string processArgs)
{
    bool success = false;
    try
    {
        pathToProcess = System.IO.Path.GetFullPath(pathToProcess);

        IntPtr DupedToken = new IntPtr(0);
        bool duplicatedToken = false;

        SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
        sa.bInheritHandle = false;
        sa.Length = Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = (IntPtr)0;

        const int SecurityImpersonation = (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation;
        const int TokenType = 1;

        duplicatedToken = DuplicateTokenEx(userToken, GENERIC_ALL_ACCESS, ref sa,                 SecurityImpersonation, TokenType, ref DupedToken);

        STARTUPINFO si = new STARTUPINFO();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = "";

        PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

        if (processArgs != null)
        {
            processArgs = " " + processArgs;
        }

        if (duplicatedToken)
        {
            success = CreateProcessAsUser(DupedToken, pathToProcess, processArgs, ref sa, ref sa, false, 0, IntPtr.Zero, null, ref si, out pi);
        }

        if (success)
        {
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
            CloseHandle(DupedToken);
        }

    }
    catch (Exception e)
    {
        success = false;
    }

    return success;
}

test.exe程序代码的简化示例

static void Main(string[] args)
{
    for (int i = 0; i < 5; i++)
    {
        String tempDir = "\\\\nasshare\\test";
        String tempFile = tempDir + "\\newfile.txt";
        // Create temp dir
        if (!System.IO.Directory.Exists(tempDir)) //This reports erroneously after first run from a reboot from createProcessAsUser within web service but works everytime when run directly from cmd on web server by same user 
        {
            System.IO.Directory.CreateDirectory(tempDir); // This fails with    System.UnauthorizedAccessException after first run from a reboot when launched from createProcessAsUser but works everytime when run directly on web server by same user directly from cmd
        }
        File.WriteAllText(tempFile, "hello world");
    }
}

0 个答案:

没有答案