从具有特定凭据的Windows服务启动进程,这是一个棘手的问题,我无法让它们在我的场景中工作。我有一个在本地系统帐户下运行的Windows服务。它有一个WCF端点侦听API请求。当通过API告知时,该服务应该在系统会话(0)中使用“工作人员”帐户凭据启动一个新进程。该进程是一个工作人员,它检查工作队列并执行此操作。如果找不到工作,它会睡一会儿,然后再检查。如果它确实找到了工作,它会在同一会话中使用相同的凭据启动一个新进程并完成该工作。工作完成后关闭。“Worker”是一个域帐户,它是计算机上本地Administrators组的成员,并且对可执行文件具有执行权限。计算机与帐户位于同一域中。问题是,当服务尝试启动进程时,它从CreateProcessAsUser方法中获取ERROR_ACCESS_DENIED(5)错误代码。我尝试在具有相同凭据的Windows7计算机上运行相同的代码并且运行良好,但是在WindowsServer2008上运行时我得到了该错误代码。代码太大,不能在这里显示,所以我把它放在别处.......该进程调用StartAsUserFromApplication方法来启动其后继程序,后者在内部调用CreateProcessWithLogonW。ImpersonationContext:http://pastie.org/private/xppc7wnoidajmpq8h8sg该服务需要获取用户令牌才能启动流程。该进程不需要启动其后继进程。据我所知,模拟在Server2008上是成功的,但它没有一些权限,我不知道是哪个。编辑:我在Windows7机器上尝试了本地管理员帐户和域帐户,它们工作正常。但是它们都不能在Server2008机器上运行。一定是某处缺少许可证,但我不知道在哪里;错误消息没有帮助。我还尝试在可执行文件的兼容性选项卡中勾选“以管理员身份运行”框,但没有任何区别。编辑:我使用ProcessMonitor查看服务中发生了什么,这就是它出错的地方......日期和时间:12/02/201411:44:03事件类:文件系统操作:CreateFile结果:访问被拒绝路径:D:..executable.exeTID:6244持续时间:0.0000450所需访问:读取数据/列表目录、执行/遍历、读取属性、同步处置:打开选项:同步IO非警报、非目录文件属性:不适用共享模式:读取,删除分配大小:不适用模拟:DomainWorker和日期和时间:12/02/201411:44:03事件类别:文件系统操作:CreateFile结果:拒绝访问路径:D:..executable.exeTID:6244Duration:0.0000480DesiredAccess:Execute/Traverse,SynchronizeDisposition:OpenOptions:SynchronousIONon-Alert,Non-Directory文件属性:n/aShareMode:Read,DeleteAllocationSize:n/aImpersonating:DomainWorker一些提示:如何在C#模拟库(类和Com类)WindowsIdentity.Impersonate方法中模拟模拟代码尝试使用此示例(在某处找到):usingSystem;使用System.Runti我.InteropServices;使用System.Security.Principal;使用System.Security.Permissions;[组件:SecurityPermissionAttribute(SecurityAction.RequestMinimum,UnmanagedCode=真)][assembly:PermissionSetAttribute(SecurityAction.RequestMinimum,Name=“FullTrust”)]公共类ImpersonationDemo{[StructLayout(LayoutKind.Sequential)]publicstructSECURITY_ATTRIBUTES{publicintLength;公共IntPtrlpSecurityDescriptor;公共布尔bInheritHandle;}公共枚举SECURITY_IMPERSONATION_LEVEL{SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation}publicenumTOKEN_TYPE{TokenPrimary=1,TokenImpersonation}[DllImport(“advapi32.dll”,CharSet=CharSet.Auto,SetLastError=true)]publicstaticexternboolLogonUser(StringlpszUsername,StringlpszDomain,StringlpszPassword,intdwLogonType,intdwLogonProvider,refIntPtrphToken);[DllImport(“kernel32.dll”,CharSet=CharSet.Auto)]privateunsafestaticexternintFormatMessage(intdwFlags,refIntPtrlpSource,intdwMessageId,intdwLanguageId,refStringlpBuffer,intnSize,IntPtr*Arguments);[DllImport(“kernel32.dll”,CharSet=CharSet.Auto)]publicexternstaticboolCloseHandle(IntPtrhandle);[DllImport(“advapi32.dll”,CharSet=CharSet.Auto,SetLastError=true)]publicexternstaticboolDuplicateToken(IntPtrExistingTokenHandle,intSECURITY_IMPERSONATION_LEVEL,refIntPtrDuplicateTokenHandle);[DllImport(“advapi32.dll”,CharSet=CharSet.Auto,SetLastError=true)]publicexternstaticboolDuplicateTokenEx(IntPtrhExistingToken,uintdwDesiredAccess,refSECURITY_ATTRIBUTESlpTokenAttributes,SECURITY_IMPERSONATION_LEVELImpersonationLevel,TOKEN_TYPETokenType,IntPtrphNewToken);//GetErrorMessage格式并返回错误消息//对应于输入的errorCodepublicunsafe静态字符串GetErrorMessage(interrorCode){intFORMAT_MESSAGE_ALLOCATE_BUFFER=0x00000100;intFORMAT_MESSAGE_IGNORE_INSERTS=0x00000200;intFORMAT_MESSAGE_FROM_SYSTEM=0x00001000;intmessageSize=255;StringlpMsgBuf=“”;intdwFlags=FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS;IntPtrptrlpSource=IntPtr.Zero;IntPtrprtArguments=IntPtr.Zero;intretVal=FormatMessage(dwFlags,refptrlpSource,errorCode,0,reflpMsgBuf,messageSize,&prtArguments);if(0==retVal){thrownewexception("Cannotformat}returnlpMsgBuf;}//TestHarness//如果将此代码合并到DLL中,请务必请求FullTrust。[PermissionSetAttribute(SecurityAction.Demand,Name="FullTrust")]publicstaticvoidMain(string[]args){IntPtrtokenHandle=newIntPtr(0);IntPtrdupeTokenHandle=newIntPtr(0);尝试{字符串用户名,机器名;//使用非托管LogonUser方法获取指定用户、计算机和密码的用户令牌。Console.Write("请输入要登录的计算机名称:");MachineName=Console.ReadLine();Console.Write("请输入您要模拟的{0}用户的登录名:",MachineName);用户名=Console.ReadLine();Console.Write("请输入{0}的密码:",UserName);constintLOGON32_PROVIDER_DEFAULT=3;//此参数使LogonUser创建主令牌。constintLOGON32_LOGON_INTERACTIVE=8;tokenHandle=IntPtr.Zero;dupeTokenHandle=IntPtr.Zero;//调用LogonUser以获取访问令牌的句柄。boolreturnValue=LogonUser(UserName,MachineName,"mm4geata",LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,reftokenHandle);Console.WriteLine("调用了LogonUser。");if(false==returnValue){intret=Marshal.GetLastWin32Error.WriteLine("LogonUser失败,错误代码:{0}",ret);Console.WriteLine("nError:[{0}]{1}n",ret,GetErrorMessage(ret));返回;}安慰。WriteLine("登录成功了吗?"+(returnValue?"Yes":"No"));Console.WriteLine("WindowsNT令牌的值:"+tokenHandle);//检查身份Console.WriteLine("ImpersonatingBefore:"+WindowsIdentity.GetCurrent().姓名);//boolretVal=DuplicateToken(tokenHandle,SecurityImpersonation,refdupeTokenHandle);SECURITY_ATTRIBUTESsa=newSECURITY_ATTRIBUTES();sa.bInheritHandle=true;sa.Length=Marshal.SizeOf(sa);sa.lpPtr)Descriptor=(0;boolretVal=DuplicateTokenEx(tokenHandle,0x10000000,refsa,SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,TOKEN_TYPE.TokenImpersonation,outdupeTokenHandle);if(false==retVal){CloseHandle("tokenHandlerite")当试图复制令牌;抛出异常。”);返回;}//传递给以下构造函数的令牌必须//是主要令牌,以便将其用于模拟。WindowsIdentitynewId=newWindowsIdentity(dupeTokenHandle);WindowsImpersonationContextimpersonatedUser=newId.Impersonate();//检查身份Console.WriteLine("Afterimpersonation:"+WindowsIdentity.GetCurrent().Name);//停止模拟用户impersonatedUser.Undo//检查身份Console.WriteLine("Afterrevoked:"+WindowsIdentity.GetCurrent().Name);//释放令牌if(tokenHandle!=IntPtr.Zero)CloseHandle(tokenHandle);如果(dupeTokenHandle!=IntPtr.Zero)CloseHandle(dupeTokenHandle);}catch(Exceptionex){Console.WriteLine("发生异常。"+ex.Message);}}}我设法让代码从这段代码开始:调用StartAsUserFromService方法,进程调用StartAsUserFromApplication方法启动其后继方法。我在LogonUser调用中使用LogonType.Batch,因为进程需要与另一个WCF服务通信,需要进行身份验证。可以使用LogonType.Network和LogonType.NetworkClearText,但是在UsingtheWorkeruseraccountintheNet.Tcpportsharingserviceiscausingpermissionissues.这个答案很有用:UsingProcess.Start()tostartaprocessasadifferentuserinaWindowsservice以上是C#学习tutorial:StartingaprocesswithspecificcredentialsfromaWindowsservice所有内容分享,如果对你有用,需要详细了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处:
