By default, when you create a named pipe under Windows, it is accessible only by other applications running under the same user account. Under XP, it worked if the two users were part of the same group, or at least did share some security policy attributes. But, for security reasons, if the background service runs as local system while the application with the user interface runs as the logged on user, you'll receive a ERROR_ACCESS_DENIED flag under Vista and Seven.

If you are willing to open up access to your pipe to all clients, you'd have to explicitly create a TSecurityAttributes record instance, initialized with full user rights:

procedure InitializeSecurity(var SA: TSecurityAttributes; var SD);
begin
fillchar(SD,SECURITY_DESCRIPTOR_MIN_LENGTH,0);
// 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;
exit; // mark OK
end;
end;
fillchar(SA,sizeof(SA),0); // mark error: no security
end;

This works fine, but it doesn't allow you remote access to a service from another computer.

I've tried to implement what Microsoft told officially on http://support.microsoft.com/kb/813414, but I didn't succeed as expected. The trick is to allow access as anonymous user to the pipe...

Here is the code I wrote from original c sample

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;
{$ALIGN ON}
type
ACE_HEADER = record
AceType: BYTE;
AceFlags: BYTE;
AceSize: WORD;
end;
ACCESS_ALLOWED_ACE = record
Header: ACE_HEADER;
Mask: ACCESS_MASK;
SidStart: DWORD;
end;
{$A8}
procedure InitializeSecurity(var SA: TSecurityAttributes; var SD);
const
SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
SECURITY_ANONYMOUS_LOGON_RID = ($00000007);
ACL_REVISION = 2;
var pSidAnonymous, pSidOwner: PSID;
dwAclSize: integer;
ACLP: PACL;
Token: THandle;
begin
fillchar(SD,SECURITY_DESCRIPTOR_MIN_LENGTH,0);
// Initialize the new security descriptor
if InitializeSecurityDescriptor(@SD, SECURITY_DESCRIPTOR_REVISION) and
GetUserSid(pSidOwner,Token) then begin
AllocateAndInitializeSid(SECURITY_NT_AUTHORITY,1,
SECURITY_ANONYMOUS_LOGON_RID,0,0,0,0,0,0,0,pSidAnonymous);
try
dwAclSize := sizeof(TACL) +
2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
GetLengthSid(pSidAnonymous) + GetLengthSid(pSidOwner) ;
ACLP := AllocMem(dwAclSize);
try
InitializeAcl(ACLP^,dwAclSize,ACL_REVISION);
if not AddAccessAllowedAce(ACLP^,ACL_REVISION,
GENERIC_ALL,pSidOwner) then
exit;
if not AddAccessAllowedAce(ACLP^,ACL_REVISION,
GENERIC_READ or GENERIC_WRITE,pSidAnonymous) then
exit;
if SetSecurityDescriptorDacl(@SD,true,ACLP,false) then begin
// Set up the security attributes structure
SA.nLength := sizeof(TSecurityAttributes);
SA.lpSecurityDescriptor := @SD;
SA.bInheritHandle := true;
exit; // mark OK
end;
finally
FreeMem(ACLP);
end;
finally
FreeSid(pSidAnonymous);
CloseHandle(Token);
end;
end;
fillchar(SA,sizeof(SA),0); // mark error: no security
end;

But it didn't work as expected. Of course, I added the name of the pipe to the SYSTEM\CurrentControlSet\Services\lanmanserver\parameters\NullSessionPipes registry entry, but it didn't work...

Whole source code is available from our source code repository, file SQLite3\SQlite3Commons.pas

You can continue to discuss on our forum, and share any solution...

Of course, we have implemented HTTP/1.1 connection, which works very well remotely over a network, so if you need networking, consider using HTTP... but it could be an interesting challenge to make named pipes work over the network!