web-dev-qa-db-ja.com

PipeSecurityが設定されている場合、名前付きパイプサーバーは2番目のインスタンスを作成するときにUnauthorizedAccessExceptionをスローします

特権のないwinformsアプリケーションと通信する(昇格された特権)サービスを作成しようとしています。 2つのコンソールアプリケーション(1つは昇格されたものではありません)が問題なく前後に話すことができましたが、サービスとwinformsアプリの実行に問題があります。

パイプの最初のインスタンスは完全に機能します。ただし、クライアントが接続して新しいインスタンスを作成しようとすると、2番目のクライアントが接続しても準備が整いますが、NamedPipeServerStreamのコンストラクターが例外をスローします

System.UnauthorizedAccessException was unhandled
  Message=Access to the path is denied.
  Source=System.Core
  StackTrace:
       at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       at System.IO.Pipes.NamedPipeServerStream.Create(String fullPipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeAccessRights rights, SECURITY_ATTRIBUTES secAttrs)
       at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights)
       at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity)
       at PipeServer.Server.Client..ctor(String pipeName, List`1 container) in E:\Visual Studio 2010\Projects\Sandbox Service\PipeServer.cs:line 27
       at PipeServer.Server.ListenForClients() in E:\Visual Studio 2010\Projects\Sandbox Service\PipeServer.cs:line 148
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

削除された例より単純なテストケースについては、下部の例を参照してください

最初の反復は正常に機能します。クライアントが接続し、client = new Clientが2回呼び出され、次にPipe = new NamedPipeServerStreamが呼び出され、例外がスローされます。

誰かが私が犯している間違いを見ることができますか?


もう少し情報があります。不思議なことに、コンソールアプリに戻りました。複数のインスタンスをテストするために、exeを複数回実行しました。同じ実行可能ファイルに2つのnew NamedPipeServerStreamを入れると、同じエラーが発生します...同じ名前付きパイプアドレスを指すサーバーとして機能する別のexeがあるのに、内部でそれを行うことが禁止されているのはなぜですか?同じexe?

static void Main()
{
    PipeAccessRule pr = new PipeAccessRule("Users", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
    PipeSecurity ps = new PipeSecurity();
    ps.AddAccessRule(pr);
    using (NamedPipeServerStream pipeServer =
        new NamedPipeServerStream("testpipe",PipeDirection.InOut,10, 
                                    PipeTransmissionMode.Message, 
                                    PipeOptions.WriteThrough,4028,4028,ps))
    using (NamedPipeServerStream pipeServer2 = //v-- Throws the execption, but if you comment this out and run the EXE twice it works fine. creating a new instance of ps and pr does not change anything.
        new NamedPipeServerStream("testpipe", PipeDirection.InOut, 10, 
                                    PipeTransmissionMode.Message,
                                    PipeOptions.WriteThrough, 4028, 4028, ps))
    {

詳しくは:

PipeSecurityを設定しないと例外はスローされませんが、セキュリティを設定すると例外がスローされます。両方のインスタンスに同じPipeSecurityを渡すか、同じ設定の2つのインスタンスを渡すかは関係ありませんが、それでも例外がスローされます。

21

同じパイプでの2番目以降のNamedPipeServerStreamのインスタンス化が失敗する原因は2つあります。

  • パイプサーバーの最初のインスタンスが作成されたときに、maxNumberOfServerInstancesctor引数が1より大きく設定されている必要があります。そうでない場合、最初のインスタンスがすでに完全に閉じられていない限り、2番目の呼び出しは失敗します。
  • ctorを呼び出すプロセスには、PipeAccessRights.CreateNewInstanceで表されるアクセス権が必要です。これは、所有者がパイプサーバーとして機能できるようにするため、パイプサーバーが嫉妬深く守るべき強力な権利です。

サービスプロセスは、パイプセキュリティを次のように設定する必要があります。

_PipeSecurity ps = new PipeSecurity(); 
    ps.AddAccessRule(new PipeAccessRule(myPipeUsersGroup, PipeAccessRights.ReadWrite, AccessControlType.Allow)); 
    ps.AddAccessRule(new PipeAccessRule(myPipeServerIdentity, PipeAccessRights.FullControl, AccessControlType.Allow)); 
_

どこ:

  • myPipeUsersGroupは、パイプに接続するすべての見込み顧客IDを含むグループのプレースホルダーです。要件/ユースケースに応じて、これは特定のクライアントID、カスタムグループ、または「ユーザー」や「管理者」などの組み込みグループの場合があります。
  • myPipeServerIdentityは、サービスIDのプレースホルダーです。これは、たとえばWindowsIdentity.GetCurrent().Ownerに設定できます。パイプサーバーがWindowsサービスでホストされている場合、サービスプロセスのログオンSID IDがさらに優れます(ただし、実装がかなり難しくなります)。これにより、特定のサービスプロセスのみがパイプのインスタンスを作成できるようになります。

パイプアクセスがローカルにログオンしているユーザーのみに制限されるようにする場合、つまりネットワークを介したリモートアクセスを防止する場合は、ネットワークユーザーの拒否ACEをパイプセキュリティACLに追加することもできます。

32
Chris Dickson

私はそれを考え出した。

static void Main()
{
    PipeSecurity ps = new PipeSecurity();
    ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
    ps.AddAccessRule(new PipeAccessRule("CREATOR OWNER", PipeAccessRights.FullControl, AccessControlType.Allow));
    ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
    ps.AddAccessRule(pa);
    using (NamedPipeServerStream pipeServer =
        new NamedPipeServerStream("testpipe",PipeDirection.InOut,10, 
                                    PipeTransmissionMode.Message, PipeOptions.WriteThrough, 1024,1024,ps))
    using (NamedPipeServerStream pipeServer2 =
        new NamedPipeServerStream("testpipe", PipeDirection.InOut, 10,
                                    PipeTransmissionMode.Message, PipeOptions.WriteThrough,1024,1024,ps))
    {

権利を追加することによりPipeAccessRights.CreateNewInstance正常に動作するようになりました。


私は別の障害にぶつかったが、それを解決したが、他の人がグーグルを通してこれを見つけた場合に備えて投稿したかった。独自のPipeセキュリティオブジェクトを提供すると、デフォルトのオブジェクトが削除されるため、必要に応じてSystemグループを再度追加して、サービスを作成している場合にパイプと通信できるようにする必要があります。上記のコードを、昇格されたサービスと昇格されていないwinformsアプリを取得して相互に通信するために使用したものに更新しました(作成者の所有者はおそらく不要です)

16

ローカライズされたバージョンのWindowsで機能するソリューション:

pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
  accessRights, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.CreatorOwnerSid, null),
  PipeAccessRights.FullControl, AccessControlType.Allow));
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
  PipeAccessRights.FullControl, AccessControlType.Allow));
3
Artem

「作成者の所有者」は、System.Security.Principal.WindowsIdentity.GetCurrent()。Nameに置き換えて、任意のユーザーのPipeAccessRights.CreateNewInstanceを削除できます。

static void Main()
{
    PipeSecurity ps = new PipeSecurity();
    ps.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite, AccessControlType.Allow));
    ps.AddAccessRule(new PipeAccessRule(System.Security.Principal.WindowsIdentity.GetCurrent().Name, PipeAccessRights.FullControl, AccessControlType.Allow));
    ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
    ps.AddAccessRule(pa);
2
Alexey

この質問に対する答えはたくさんあることは知っていますが、名前付きパイプがあるプロジェクトのapp.manifestファイルでrequestedExecutionLevelのレベルをrequireAdministratorに設定することで、同様の問題を修正しましたコードが存在します。そしてこれは私のためのUnauthorizedAccessExceptionを修正しました

1
Quintonn

これにより、サーバーにアクセスできるようになります全員読み取りと書き込みが可能です。ユーザー名がハードコーディングされていないため、すべての言語のOSでも機能します。

public NamedPipeServerInstance(string pipeName, int maxNumberOfServerInstances)
{
    var ps = new PipeSecurity();
    var sid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
    var everyone = sid.Translate(typeof(NTAccount));
    ps.SetAccessRule(new PipeAccessRule(everyone,
        PipeAccessRights.ReadWrite, AccessControlType.Allow));

    server = new NamedPipeServerStream(pipeName,
        PipeDirection.InOut,
        maxNumberOfServerInstances,
        PipeTransmissionMode.Message,
        PipeOptions.Asynchronous,
        4028, 4028, ps);

    var asyncResult = server.BeginWaitForConnection(OnConnected, null);
}

client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out, PipeOptions.Asynchronous);
0

私の場合、サーバー側は管理者ユーザーとして実行されており、クライアント側は通常のユーザーとして実行されています。したがって、解決策は、同じIDを使用してそれらを再度開くことです。

0
Sanbrother