Сервер именованных каналов создает исключение UnauthorizedAccessException при создании второго экземпляра, если установлен параметр PipeSecurity - PullRequest
18 голосов
/ 13 августа 2010

Я пытаюсь написать службу (с повышенными привилегиями), которая будет общаться с непривилегированным приложением winforms. У меня было два консольных приложения (одно с повышенными правами, а не одно) без проблем, но у меня возникли проблемы с обслуживанием и приложением winforms.

Первый экземпляр трубы работает отлично. Однако после того, как мой клиент подключается, и я пытаюсь создать новый экземпляр, чтобы он был готов, если подключится второй клиент, но конструктор для 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 вызывается во второй раз, что, в свою очередь, вызывает Pipe = new NamedPipeServerStream, и это вызывает исключение.

Кто-нибудь может увидеть, какую ошибку я совершаю?


Немного больше информации, из любопытства я вернулся к своему консольному приложению. Чтобы протестировать несколько экземпляров, я просто запускал exe несколько раз. Когда я помещаю два new NamedPipeServerStream в один и тот же исполняемый файл, я получаю одну и ту же ошибку ... Так почему же это нормально, если у вас есть отдельный 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 или два экземпляра с одинаковыми настройками, он все равно выдает исключение.

Ответы [ 6 ]

28 голосов
/ 07 декабря 2010

Есть две вещи, которые могут вызвать сбой создания экземпляра второго или последующего NamedPipeServerStream в том же канале:

  • аргумент ctor maxNumberOfServerInstances должен быть установлен более чем на 1, когда первый экземпляртрубного сервера был создан.Если нет, второй вызов завершится неудачно, если только первый экземпляр не был полностью закрыт.
  • процесс, вызывающий 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 - это заполнитель для группы, которая содержитвсе предполагаемые идентификаторы клиентов, которые будут подключаться к каналу.В зависимости от ваших требований / варианта использования это может быть конкретный идентификатор клиента, пользовательская группа или встроенная группа, например «Пользователи» или «Администраторы».
  • myPipeServerIdentity - это заполнитель для идентификатора службы.,Это может быть установлено, например, на WindowsIdentity.GetCurrent().Owner.Когда сервер канала размещен в службе Windows, тогда еще лучше (но гораздо сложнее реализовать) будет идентификатор SID входа в систему процесса службы - это будет гарантировать, что только конкретный процесс службы может создавать экземпляры канала.

Если вы хотите, чтобы доступ к каналу был ограничен только пользователями, вошедшими в систему локально, т.е. для предотвращения удаленного доступа через сеть, вы также можете добавить запрещающий ACE для пользователей сети в ACL безопасности канала.

15 голосов
/ 13 августа 2010

Я понял это.

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 теперь работает нормально.


Я столкнулся с еще одной загадкой, но решил ее, но хотел опубликовать на случай, если другие найдут это через Google. предоставляя свой собственный объект безопасности Pipe, он удаляет объект по умолчанию, поэтому, если вам это нужно, вам нужно повторно добавить группу System, чтобы он мог общаться с конвейером, если вы пишете сервис. Я обновил свой код, приведенный выше, до того, что использовал для получения повышенных услуг и приложения без повышенных форм winforms для общения друг с другом (владелец-создатель, скорее всего, не нужен)

3 голосов
/ 19 июня 2012

Решение, которое работает на локализованных версиях 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));
2 голосов
/ 16 июня 2011

«Владелец-создатель» можно заменить на System.Security.Principal.WindowsIdentity.GetCurrent (). Назовите и удалите 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);
0 голосов
/ 05 декабря 2018

Это сделает сервер доступным для каждого для чтения и записи. Он также будет работать в ОС со всеми языками, так как имя пользователя не жестко запрограммировано

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 голосов
/ 04 марта 2015

Я знаю, что есть много ответов на этот вопрос, но я исправил подобную проблему, установив уровень requiredExecutionLevel в requireAdministrator в файле app.manifest проекта, где мой Код namedpipe находится постоянно. И это исправило UnauthorizedAccessException для меня

...