Именованные каналы из службы Windows в клиентское приложение - PullRequest
10 голосов
/ 13 июля 2011

Моя история в том, что я разрабатываю новое приложение, которое должно взаимодействовать со службой Windows.После долгих исследований я пришел к выводу, что именованные каналы являются рекомендуемым методом ( Как отправить строку из одного экземпляра моей программы Delphi в другой? ), однако, похоже, что я не могу использоватьSendMessage или Named Pipes в Win7 из-за проблем с безопасностью ... сообщения никогда не доходят до службы за пределами приложения.

Я использую именованные компоненты Pipe Рассела Либби, которые работают без помех между обычными настольными приложениями,но служба Windows, кажется, бросает рывок в решении.Дальнейшие исследования говорят мне, что может быть возможно открыть защиту с обеих сторон, чтобы позволить им общаться, однако мой уровень знаний по этому вопросу в лучшем случае минимален, и я не смог разобраться в возможных вызовах API.

Основываясь на компоненте pipe.pas Delphi, что нужно сделать, чтобы открыть этого ребенка, чтобы обе стороны могли начать разговор?Я уверен, что следующие две функции из файла pipe.pas идентифицируют атрибуты безопасности, кто-нибудь может мне помочь?

Спасибо!

procedure InitializeSecurity(var SA: TSecurityAttributes);
var
  sd: PSecurityDescriptor;
begin

  // Allocate memory for the security descriptor
  sd := AllocMem(SECURITY_DESCRIPTOR_MIN_LENGTH);

  // Initialize the new security descriptor
  if InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION) then
  begin
    // Add a NULL descriptor ACL to the security descriptor
    if SetSecurityDescriptorDacl(sd, True, nil, False) then
    begin
      // Set up the security attributes structure
      SA.nLength := SizeOf(TSecurityAttributes);
      SA.lpSecurityDescriptor := sd;
      SA.bInheritHandle := True;
    end
    else
      // Failed to init the sec descriptor
      RaiseWindowsError;
  end
  else
    // Failed to init the sec descriptor
    RaiseWindowsError;

end;

procedure FinalizeSecurity(var SA: TSecurityAttributes);
begin

  // Release memory that was assigned to security descriptor
  if Assigned(SA.lpSecurityDescriptor) then
  begin
    // Reource protection
    try
      // Free memory
      FreeMem(SA.lpSecurityDescriptor);
    finally
      // Clear pointer
      SA.lpSecurityDescriptor := nil;
    end;
  end;

end;

Ответы [ 5 ]

8 голосов
/ 14 июля 2011

Windows Vista, Seven и 2008 обеспечивают более безопасное использование именованных каналов, см., Например, http://blogs.technet.com/b/nettracer/archive/2010/07/23/why-does-anonymous-pipe-access-fail-on-windows-vista-2008-windows-7-or-windows-2008-r2.aspx

1 голос
/ 19 июля 2013

Когда мы перевели наш продукт с Win 2K на Win7, мы запустили нашу именованную трубу и перестали работать. После двух недель разговоров с MS (и $ 275) мы обнаружили, что это вызвано настройками файла Use Shared Folders. Снятие отметки с этой функции позволило нам продолжить с трубами.

1 голос
/ 14 июля 2011

Я попытался реализовать это:

function GetUserSid(var SID: PSID; var Token: THandle): boolean;
var TokenUserSize: DWORD;
    TokenUserP: PSIDAndAttributes;
begin
  result := false;
  if not OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, Token) then
    if (GetLastError <> ERROR_NO_TOKEN) or
       not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token) then
      Exit;
  TokenUserP := nil;
  TokenUserSize := 0;
  try
    if not GetTokenInformation(Token, TokenUser, nil, 0, TokenUserSize) and
       (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
      Exit;
    TokenUserP := AllocMem(TokenUserSize);
    if not GetTokenInformation(Token, TokenUser, TokenUserP,
       TokenUserSize, TokenUserSize) then
      Exit;
    SID := TokenUserP^.Sid;
    result := true;
  finally
    FreeMem(TokenUserP);
  end;
end;

function ConvertSidToStringSidA(aSID: PSID; var aStr: PAnsiChar): BOOL; stdcall; external advapi32;
function ConvertStringSecurityDescriptorToSecurityDescriptorA(
  StringSecurityDescriptor: PAnsiChar; StringSDRevision: DWORD;
  SecurityDescriptor: pointer; SecurityDescriptorSize: Pointer): BOOL; stdcall; external advapi32;

const
  SDDL_REVISION_1 = 1;

procedure InitializeSecurity(var SA: TSecurityAttributes; var SD; Client: boolean);
var OK: boolean;
    Token: THandle;
    pSidOwner: PSID;
    pSid: PAnsiChar;
    SACL: AnsiString;
begin
  fillchar(SD,SECURITY_DESCRIPTOR_MIN_LENGTH,0);
  // Initialize the new security descriptor
  OK := false;
  if InitializeSecurityDescriptor(@SD, SECURITY_DESCRIPTOR_REVISION) then begin
    if Client or (OSVersionInfo.dwMajorVersion<6) then
      // before Vista: add a NULL descriptor ACL to the security descriptor
      OK := SetSecurityDescriptorDacl(@SD, true, nil, false)
     else begin
      // since Vista: need to specify special ACL
      if GetUserSid(pSidOwner,Token) then
      try
        if ConvertSidToStringSidA(pSidOwner,pSid) then
        try
          SACL := 'D:(A;;GA;;;'+pSID+')(A;;GWGR;;;AN)(A;;GWGR;;;WD)S:(ML;;NW;;;S-1-16-0)';
          OK := ConvertStringSecurityDescriptorToSecurityDescriptorA(
            pointer(SACL),SDDL_REVISION_1,@SD,nil);
        finally
          LocalFree(PtrUInt(pSid));
        end;
      finally
        FreeSid(pSidOwner);
        CloseHandle(Token);
      end;
    end;
  end;
  if OK then begin
    // Set up the security attributes structure
    SA.nLength := sizeof(TSecurityAttributes);
    SA.bInheritHandle := true;
    SA.lpSecurityDescriptor := @SD;
  end else
    fillchar(SA,sizeof(SA),0); // mark error: no security
end;

Кажется, он работает на стороне сервера (то есть атрибуты безопасности создаются как положено), и вам придется писать код на стороне клиента, беззабыть добавить имя канала в ключ реестра SYSTEM \ CurrentControlSet \ Services \ lanmanserver \ parameters \ NullSessionPipes , как и ожидалось.

0 голосов
/ 15 декабря 2015

У меня была такая же проблема, и я просто решил ее. Для меня причина, по которой это не сработало, заключалась в том, что у реализации Russels TPipe есть проверка идентификаторов потоков непосредственно перед созданием Pipe: if not(Sync.SyncBaseTID = FNotifyThread) then..

Оказалось, я создавал TPipeServer в неправильном месте в моем сервисе. (Я переопределил DoStart и т. Д. Вместо использования события OnStart ... не делайте этого!) Сейчас я создаю экземпляр TPipeServer в том же потоке, в котором позже активирую его.

0 голосов
/ 15 июля 2011

Кажется, я помню, что RemObjects имеет именованный канал клиент / серверный элемент управления в своем пакете. Если у вас нет ограниченного бюджета, я настоятельно рекомендую вам взглянуть на готовые компоненты для подобных вещей. Это и трудоемкий, и хитрый, чтобы получить право.

Кроме того, у Джастина Смита есть статья о именованных каналах прямо сейчас. Проверьте его блог на эту тему здесь: http://smythconsulting.blogspot.com/2011/07/smartmediaplayer-pipes-part4.html

Удачи!

...