3

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

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

在 Web 服务器干净启动时,该进程可以在网络共享目录 (\\nasshare\test) 上一遍又一遍地调用 System.IO.Directory.Exists 并获得正确的响应。但是,当进程结束并再次调用 Web 服务以再次启动进程时,它将报告该目录不再存在,然后我的程序代码尝试创建据称丢失的目录并失败并出现异常消息:System. UnauthorizedAccessException:对路径“\\nasshare\test”的访问被拒绝。

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

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

简化的 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");
    }
}
4

0 回答 0