什么可能导致通过CreateProcessAsUser从Web服务创建的连续进程使用委派在尝试访问网络共享时遇到System.UnauthorizedAccessException异常?
WCF Rest Web服务使用带有重复用户令牌的CreateProcessAsUser启动新进程。该过程启动并报告它由拥有该共享访问权限的模拟用户拥有。
在Web服务器的干净启动时,进程可以在网络共享目录(\\ nasshare \ test)上反复调用System.IO.Directory.Exists并获得正确的响应。但是,当进程结束并再次调用Web服务再次启动进程时,它将报告该目录不再存在,然后我的程序代码尝试创建所谓的缺失目录并失败,并显示异常消息:System。 UnauthorizedAccessException:拒绝访问路径'\\ nasshare \ test'。
奇怪的是,如果我重新启动网络服务器,它将再次运行......直到流程结束。 Web服务创建的连续进程将失败。当我从Web服务器上的命令提示符运行该进程时,进程可以看到该文件夹并写入该文件夹。我可以通过这种方式反复运行该过程,并且在使用Web服务器中的CreateProcessAsUser启动失败后,它甚至会立即正常工作。
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");
}
}