使用Net.Tcp端口共享服务时拒绝访问

时间:2014-02-13 08:28:24

标签: c# winapi process account net.tcp

这个问题与Starting processes under specific credentials from a Windows service有关,但这是一个不同的问题。

我已在特定凭据下从系统会话(0)中的Windows服务启动了一个进程,但它无法侦听端口共享URL。它在Windows Server 2008计算机上使用“Worker”域帐户。

我的 SMSvcHost.exe.config 文件:http://pastie.org/private/jxed8bdft0eir5uc371pq

我已经重新启动了服务和机器,但它仍然给了我这个例外:

System.ServiceModel.CommunicationException: The service endpoint failed to listen on the URI 'net.tcp://localhost:5400/Agent/384' because access was denied.  Verify that the current user is granted access in the appropriate allowAccounts section of SMSvcHost.exe.config. ---> System.ComponentModel.Win32Exception: Access is denied
   at System.ServiceModel.Activation.SharedMemory.Read(String name, String& content)
   at System.ServiceModel.Channels.SharedConnectionListener.SharedListenerProxy.ReadEndpoint(String sharedMemoryName, String& listenerEndpoint)

启动流程的 ProcessHelper 代码:http://pastie.org/private/iytqehsdfujrgil1decda。我正在调用StartAsUserFromService方法。

我认为配置中的SID与进程正在运行的帐户之间的链接是以某种方式进行的。但为什么呢?

编辑:

我已经仔细检查了我正在编辑的配置是否被该服务使用。我已经尝试明确添加系统帐户和Everyone,但它仍然给我一个访问被拒绝错误。这就像它根本没有看那个配置。

如何找到遗失权限的位置?

编辑:

我在机器上重新安装了.NET 4.5.1并且所有Windows更新仍然没有运气。

编辑:

这是复制用户令牌以允许其使用端口共享的正确方法吗?特别是SecurityDescriptor位?

private static ImpersonationResult ImpersonateUser(string domain, string username, string password)
{
    IntPtr token = IntPtr.Zero;
    IntPtr primaryToken = IntPtr.Zero;

    try
    {
        // Get token
        bool bImpersonated = LogonUser(
            username,
            domain,
            password,
            (int)LogonType.NetworkClearText,
            (int)LogonProvider.Default,
            ref token);

        if (!bImpersonated)
        {
            throw new Exception(string.Format("Failed to impersonate identity. Error code: {0}", Marshal.GetLastWin32Error()));
        }

        SecurityDescriptor sd = new SecurityDescriptor();
        IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(sd));
        Marshal.StructureToPtr(sd, ptr, false);
        InitializeSecurityDescriptor(ptr, 1);
        sd = (SecurityDescriptor)Marshal.PtrToStructure(ptr, typeof(SecurityDescriptor));

        // Set up security
        bool bDecriptorSet = SetSecurityDescriptorDacl(
            ref sd,
            true,
            IntPtr.Zero,
            false);

        if (!bDecriptorSet)
        {
            throw new Exception(string.Format("Failed to set security descriptor. Error code: {0}", Marshal.GetLastWin32Error()));
        }

        SecurityAttributes processAttributes = new SecurityAttributes();
        processAttributes.lpSecurityDescriptor = ptr;
        processAttributes.nLength = (uint)Marshal.SizeOf(sd);
        processAttributes.bInheritHandle = true;

        // Duplicate token
        bool bTokenDuplicated = DuplicateTokenEx(
            token,
            0,
            ref processAttributes,
            (int)SecurityImpersonationLevel.SecurityImpersonation,
            (int)TokenType.TokenPrimary,
            ref primaryToken);

        if (!bTokenDuplicated)
        {
            throw new Exception(string.Format("Failed to duplicate identity token. Error code: {0}", Marshal.GetLastWin32Error()));
        }

        SecurityAttributes threadAttributes = new SecurityAttributes();
        threadAttributes.lpSecurityDescriptor = IntPtr.Zero;
        threadAttributes.nLength = 0;
        threadAttributes.bInheritHandle = false;

        // Got the token
        return new ImpersonationResult()
            {
                Token = primaryToken,
                ProcessAttributes = processAttributes,
                ThreadAttributes = threadAttributes
            };
    }
    finally
    {
        FreeToken(token);
    }
}

private static void FreeToken(IntPtr token)
{
    if (token != IntPtr.Zero)
    {
        CloseHandle(token);
    }
}

编辑:

以下是我的进程的app.config位,它启用了端口共享:http://pastie.org/private/8ekqeps4d7rmo7hnktsw

这是启动流程的服务的app.config位:http://pastie.org/private/nqqcwz8bvjb5fzp48yavbw。使用端口共享没有问题,因为它在系统帐户下运行。

端口共享服务本身已启用,我已经提到我已多次重启机器。

未安装“Application Server”角色,但是当我添加它时,TCP端口共享角色已经勾选并显示为灰色,因此必须安装其他东西。它是否附带.NET 4.5.1?

3 个答案:

答案 0 :(得分:1)

前言:请用一个问题一个线程......

PortSharing:您在哪里启用了端口共享?我们在您的配置文件中看不到这一点。有关更多信息,请参阅:如何:Configure a Windows Communication Foundation Service to Use Port Sharing

您是否在服务器上安装了“Application Server”角色?另见:Checklist: Use TCP Port Sharing to Allow Multiple WCF Applications to Use the Same TCP Port

系统上是否启用了端口共享?请参阅:How to: Enable the Net.TCP Port Sharing Service

另外,你重启了服务器吗?有时这是必需的(或至少所有使用此端口的服务),请参阅:http://blogs.msdn.com/b/joncole/archive/2010/06/10/tcp-port-sharing-access-is-denied.aspx

有关端口共享的全面说明是:http://blogs.msdn.com/b/andreal/archive/2009/04/05/net-tcp-ip-port-sharing.aspx

另请注意,如果需要,您必须添加一些帐户以进行激活: Configuring the Net.TCP Port Sharing Service

您确定 SmSvcHost.exe.config 允许从您的帐户进行访问,您的进程是否正在运行?

<configuration>
  <system.serviceModel.activation>
   <net.tcp listenBacklog="16" <!—16 * # of processors -->
      maxPendingAccepts="4"<!— 4 * # of processors -->
      maxPendingConnections="100"
      receiveTimeout="00:00:30" <!—30 seconds -->
      teredoEnabled="false">
      <allowAccounts>
         <!-- LocalSystem account -->
         <add securityIdentifier="S-1-5-18"/>
         <!-- LocalService account -->
         <add securityIdentifier="S-1-5-19"/>
         <!-- Administrators account -->
         <add securityIdentifier="S-1-5-20"/>
         <!-- Network Service account -->
         <add securityIdentifier="S-1-5-32-544" />
         <!-- IIS_IUSRS account (Vista only) -->
         <add securityIdentifier="S-1-5-32-568"/>
       </allowAccounts>
   </net.tcp>
 </system.serviceModel.activation>

答案 1 :(得分:1)

事实证明,登录类型导致权限无法与端口共享服务一起正常运行。我将其更改为LogonType.Batch并开始工作。

完整代码:

ProcessHelper http://pastie.org/private/dlkytj8rbigs8ixwtg

TokenImpersonationContext http://pastie.org/private/nu3pvpghoea6pwwlvjuq

答案 2 :(得分:0)

(只是另一个可能对某人有帮助的答案)

事实证明,在我的情况下,登录用户没有管理权限。 将帐户类型更改为管理员解决了问题。 我也没有改变SmSvcHost.exe.config

中的任何内容