none
Named Pipes Not Working When Logged In As a Standard User in Vista

    Question

  • Hi,

    I'm using named pipes to communicate between processes.
    The processes run at different integrity levels - LOW (ie toolbar) + MEDIUM (tray icon) + HIGH + SYSTEM (service).
    I'm defining a LOW integrity SACL when creating the named pipe.
    Things work great when logged in as an Administrator.
    When logged in as a Standard User however, only processes of identical integrity levels can communicate with one another because CreateFile fails to open an existing pipe with erorr ACCESS DENIED  (eg: MED to MED works, HIGH to HIGH works, ...)
    I need both READ and WRITE access to the pipe.

    What security attribute do I need to pass to CreateNamedPipe() to resolve this?
    Do I have to call SetSecurityInfo() after calling CreateNamedPipe() to resolve this somehow?

    I've spent a full day searching and trying various DACLs and SACLs and i've hit a brick wall.
    I'm crossing my fingers that someone can point me in the right direction.
    The problem is mentioned in this thread but no solution is offered:
    http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/ce75cdbd-a7c9-422f-b8e6-49ea4b4aa97f

    Relevant Code (error checking removed):
    =========

    LPCWSTR LOW_INTEGRITY_SDDL_SACL_W = L"S:(ML;;NW;;;LW)"
    ;
    PSECURITY_DESCRIPTOR securitydescriptor;
    ConvertStringSecurityDescriptorToSecurityDescriptorW(LOW_INTEGRITY_SDDL_SACL_W,SDDL_REVISION_1,&securitydescriptor,NULL);
    sa.nLength = sizeof
    (SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = securitydescriptor;
    sa.bInheritHandle = TRUE;
    
        HANDLE pipe = CreateNamedPipe(pipename,                    // pipe name 
    
                                      PIPE_ACCESS_DUPLEX,          // read/write access 
    
                                      PIPE_TYPE_MESSAGE |          // message type pipe 
    
                                      PIPE_READMODE_MESSAGE |      // message-read mode 
    
                                      PIPE_WAIT,                   // blocking mode 
    
                                      PIPE_UNLIMITED_INSTANCES,    // max. instances  
    
                                      PIPESERVER_OUTPUTBUFFERSIZE, // output buffer size 
    
                                      PIPESERVER_INPUTBUFFERSIZE,  // input buffer size 
    
                                      0,                           // client time-out 
    
                                      &sa);                        // security attribute
    
    
    
    <...create another LOW integrity psa...>

     HANDLE pipe = CreateFile(pipename, // pipe name
    GENERIC_READ | // read and write access
    GENERIC_WRITE,
    0, // no sharing
    psa, // default security attributes
    OPEN_EXISTING, // opens existing pipe
    0, // default attributes
    NULL); // no template file

    Thanks,
    Ignac

    Thursday, January 21, 2010 10:20 PM

Answers

  • I had a similar problem in .NET.  I assume you know C# since the link you provided was .NET.  This allowed Users to contact a named pipe server running in a service:

                pipeSecurity = new PipeSecurity();
                var usersPipeAccessRule = new PipeAccessRule(
                    new SecurityIdentifier( WellKnownSidType.BuiltinUsersSid, null ),
                    PipeAccessRights.ReadWrite | PipeAccessRights.Synchronize,
                    AccessControlType.Allow
                    );
                pipeSecurity.AddAccessRule(usersPipeAccessRule)
    
                    waitingPipe = new NamedPipeServerStream(
                        PipeName,
                        PipeDirection.InOut,
                        NamedPipeServerStream.MaxAllowedServerInstances,
                        PipeTransmissionMode.Message,
                        PipeOptions.Asynchronous,
                        ServicePipeProcessor.MaxBufferSize,
                        ServicePipeProcessor.MaxBufferSize,
                        pipeSecurity);


    I would assume you would want to use functions like CreateWellKnownSid and SetSecurityDescriptotDacl to do the same thing.

    • Marked as answer by Ignac Vucko Saturday, January 23, 2010 9:22 PM
    Friday, January 22, 2010 4:14 PM

All replies

  • I had a similar problem in .NET.  I assume you know C# since the link you provided was .NET.  This allowed Users to contact a named pipe server running in a service:

                pipeSecurity = new PipeSecurity();
                var usersPipeAccessRule = new PipeAccessRule(
                    new SecurityIdentifier( WellKnownSidType.BuiltinUsersSid, null ),
                    PipeAccessRights.ReadWrite | PipeAccessRights.Synchronize,
                    AccessControlType.Allow
                    );
                pipeSecurity.AddAccessRule(usersPipeAccessRule)
    
                    waitingPipe = new NamedPipeServerStream(
                        PipeName,
                        PipeDirection.InOut,
                        NamedPipeServerStream.MaxAllowedServerInstances,
                        PipeTransmissionMode.Message,
                        PipeOptions.Asynchronous,
                        ServicePipeProcessor.MaxBufferSize,
                        ServicePipeProcessor.MaxBufferSize,
                        pipeSecurity);


    I would assume you would want to use functions like CreateWellKnownSid and SetSecurityDescriptotDacl to do the same thing.

    • Marked as answer by Ignac Vucko Saturday, January 23, 2010 9:22 PM
    Friday, January 22, 2010 4:14 PM
  • Thanks for your reply Eric!

    Based on your reply, I had some success using a similar technique to the one you provided - I'm actually working in C++.
    Everything works great, except for one critical thing: communication with LOW integrity processes is not working.

    Before, I would explicitly specify a LOW integrity SACL during pipe creation (see orignal code paste above).
    Now, I'm instead setting a DACL to allow "EVERYONE' access during pipe creation (see code below).
    But, I can't seem to get it to recognize both the LOW integrity SACL and the EVERYONE DACL.
    Here's what I've tried:
    1) Call CreateNamedPipe() with a LOW integrity SACL and then try to add the Everyone DACL to the returned pipe handle
    2) Call CreateNamedPipe() with the Everyone DACL and then try to add the LOW integrity SACL to the returned pipe handle

    Neither seem to work...it seems that the security attribute MUST be specified upfront when the named pipe is created.

    Would you know how I can augment the code below to specify a LOW integrity SACL?

    - I've tried defining another EXPLICIT_ACCESS structure using SET_AUDIT_SUCCESS without luck
    - I've also tried using ConvertStringSecurityDescripterToSecurityDescriptorW() rather than simply doing a LocalAlloc of SECURITY_DESCRIPTOR, but that doesn't seem to work either
    - I'm sure I'm doing something wrong: this SACL/DACL stuff is mind boggling (at least for me).

    Again, I really appreciate your reply Eric,
    Ignac,

    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
    PSID everyone_sid = NULL;
    AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid);
    
    EXPLICIT_ACCESS ea;
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea.Trustee.ptstrName  = (LPWSTR)everyone_sid;
    
    PACL acl = NULL;
    SetEntriesInAcl(1, &ea, NULL, &acl);
    
    // HOW DO I ADD A LOW INTEGRITY SACL HERE THAT WILL NOT BE IGNORED ?

    PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH); InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE); SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = sd; sa.bInheritHandle = FALSE; CreateNamedPipe(...,&sa);


    Friday, January 22, 2010 5:35 PM
  • Congratulations on the progress.  It seems like it would work for low integrity since it's working for medium.  Have you tried this using SECURITY_NULL_SID_AUTHORITY for the SID_IDENTIFIER_AUTHORITY or adding a second entry in the ACL?
    Friday, January 22, 2010 6:12 PM
  • Here's what I have tried:
    hi Eric,

    - SECURITY_NULL_SID_AUTHORITY does not work (even non-low processes can't communicate)

    - tried merging in an SACL entry in the ACL using EXPLICIT_ACCESS and an access mode of SET_AUDIT_SUCCESS, but it doesn't seem to have any effect (or i'm doing something wrong). 

    - tried getting SECURITY_NULL_SID_AUTHORITY privilege, calling CreateNamedPipe with ACCESS_SYSTEM_SECURITY , and then adding a low integrity SACL after the call to CreateNamedPipe in two ways:

       a) Using SetSecurityInfo() => fails with ACCESS_DENIED
       b) Using SetEntriesInAcl() => no errors, but no effect

        Also, if I grab ACCESS_SYSTEM_SECURITY it makes things wors.
        Without it communication is only broken from LOW integrity to higher integriy but the reverse works.
        With it, communication is broken in both directions.

    Thanks,
    Ignac

    Friday, January 22, 2010 7:19 PM
  • I'm not sure if it would be any different, but try something like this:

    bool AddWellKnowSid(WELL_KNOWN_SID_TYPE WellKnownSidType, PACL pAcl)
    {
        bool returnValue = false;
        DWORD sidSize = SECURITY_MAX_SID_SIZE;
        PSID sid = LocalAlloc(LMEM_FIXED, sidSize);
    
        if(sid != NULL)
        {    
            if(CreateWellKnownSid(WellKnownSidType, NULL, sid, &sidSize))
            {
                if (AddAccessAllowedAce(pAcl, ACL_REVISION, 0xFFFF, sid))
                {
                    returnValue = true;
                }
            }
    
            LocalFree(sid);
        }
    
        return returnValue;
    }
    
    void Create()
    {
        DWORD cbAcl = 256;
        PACL pAcl = (ACL*)LocalAlloc(LPTR, cbAcl);
        if (pAcl == NULL)
            return;
    
        if (InitializeAcl(pAcl, cbAcl, ACL_REVISION))
        {
            if (AddWellKnowSid(WinAnonymousSid, pAcl) && 
                AddWellKnowSid(WinWorldSid, pAcl))
            {
                PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); 
                if (InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
                {
                    if (SetSecurityDescriptorDacl(pSD, TRUE, pAcl, FALSE))
                    {
                        SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), pSD, FALSE};
                        HANDLE hPipe = CreateNamedPipe(_T("\\\\.\\pipe\\namedpipe"),
                            PIPE_ACCESS_DUPLEX,
                            PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT,
                            PIPE_UNLIMITED_INSTANCES, 512, 512, 0, &sa);
                        if (hPipe != INVALID_HANDLE_VALUE)
                        {
                            CloseHandle(hPipe);
                        }
                    }
                }
            }
        }
    
        LocalFree(pAcl);
    }
    
    Friday, January 22, 2010 9:21 PM
  • hi Eric,

    Thanks for the code.
    I tried it but it didn't work for me - a high integrity process could not talk to a medium integrity process if standard user.
    The DACL code I pasted earlier seems to solve that part for me...it's the low integrity SACL that I'm having issues with.
    Here's the code I try to use to set the SACL after creating the pipe handle....I cant figure out why SetSecurityInfo is returning ACCESS_DENIED.

    1. Use AdjustTokenPrivileges() to grab SE_SECURITY_NAME
    2. Specify the ACCESS_SYSTEM_SECURITY flag when calling CreateNamedPipe()
    3. Call the below function as follows: SetObjectToLowIntegrity(pipe,SE_KERNEL_OBJECT);


    bool SetObjectToLowIntegrity(HANDLE hObject,SE_OBJECT_TYPE type)
    {
      LPCWSTR LOW_INTEGRITY_SDDL_SACL_W = L"S:(ML;;NW;;;LW)";

      bool  bRet           = false;
      DWORD dwErr          = ERROR_SUCCESS;
      PACL  pSacl          = NULL;
      BOOL  fSaclPresent   = FALSE;
      BOOL  fSaclDefaulted = FALSE;
      PSECURITY_DESCRIPTOR pSD = NULL;
      
      if (ConvertStringSecurityDescriptorToSecurityDescriptorW(LOW_INTEGRITY_SDDL_SACL_W,SDDL_REVISION_1,&pSD,NULL))
      {
        if (GetSecurityDescriptorSacl(pSD,&fSaclPresent,&pSacl,&fSaclDefaulted))
        {
          dwErr = SetSecurityInfo(hObject,type,LABEL_SECURITY_INFORMATION,NULL,NULL,NULL,pSacl); // --------> FAILS WITH ACCESS_DENIED
          bRet = (ERROR_SUCCESS == dwErr);
        }
        LocalFree ( pSD );
      }
      
      return bRet;
    }
    Saturday, January 23, 2010 3:01 AM
  • hi Eric,

    Thanks for your suggestions.

    I FINALLY got it working.
    Man this stuff is as clear as mud.

    It seems that there is no way to modify the permissions of a named pipe after it has been created.
    I tried and it always either simply doesn't work or returns ACCESS_DENIED.
    So, I had to specify both the DACL and SACL up front when creating the pipe.

    The DACL code was pasted above in an earlier thread and the SACL can be created as follows:

    1. Create a new using InitializeAcl()
    2. Initialize a new SID specifying 'SECURITY_MANDATORY_LOW_RID'
    3. Call AddMandatoryAce() to add the SID to the ACL
    4. Call SetSecurityDescriptorSacl() to add the ACL to the security descriptor

    Cheers,
    Ignac
    • Proposed as answer by DesertSerenity Monday, February 25, 2013 8:54 AM
    • Unproposed as answer by DesertSerenity Monday, February 25, 2013 8:54 AM
    • Proposed as answer by Com3t Sunday, May 05, 2013 8:22 AM
    Saturday, January 23, 2010 9:22 PM
  • Congratulations!!  That's a pretty good puzzle you figured out.

    Saturday, January 23, 2010 9:49 PM
  • Do you have full sample code you can post. I am trying to accomplish this same thing and even with the code you have pasted here so far, I am having no luck.

    Thanks
    Saturday, February 27, 2010 7:05 AM
  • Hello

    You can check out the full named pipe sample in Microsoft All-In-One Code Framework:

    http://1code.codeplex.com

    See the C# version: CSNamedPipeServer, CSNamedPipeClient
    C++ version: CppNamedPipeServer, CppNamedPipeClient
    VB.NET version: VBNamedPipeServer, VBNamedPipeClient

    These samples have been fully tested in various Windows environments (e.g. high integrity level env, x64, pre-Vista env, etc)

    If you have any feedback of the samples, please feel free to email to codefxf@microsoft.com

     

     


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Proposed as answer by Com3t Sunday, May 05, 2013 8:23 AM
    • Unproposed as answer by Com3t Sunday, May 05, 2013 8:23 AM
    Thursday, March 25, 2010 5:35 AM
    Moderator
  • After 2 days of working on it, I've confirmed that Ignac approach does work correctly.  As he suggested, it seems to be impossible to set the SACL on the pipe after it has been created.

    I found this out when I tried to set PipeAccessRule and PipeAuditRule on a Pipe using the NamedPipeServerStream class in System.IO.Pipes.  I'm assuming that behind the scenes the NamedPipeServerStream constructor creates the pipe first and then tries setting the SACL/DACL.  As a result, the constructor fails telling you that you don't have sufficient privileges to perform the action (or something similar)

    I developed Ignac's solution using C#, but then once I'd successfully created the pipe with the correct security attributes, I passed the pipe handle into the NamedPipeServerStream constructor.  This seems to be working ok and now I can use NamedPipeServerStream to work with a pipe that can be accessed by Everyone and by low integrity processes as well.

    If someone has questions on this issue I'd be happy to help guide you.

     

    David K

    Wednesday, December 08, 2010 2:13 AM
  • Hello, I have checked the All-in-One examples.But they also giving the same problem as "Access Denied".In my case I have Piped Server in Windows Service and client is in .dll program.So is there any different method for PIPES when called from dll ?

    Please help as I am going nuts over here looking for this... I have tried all the possible solutions I have found but nothing is working

    Wednesday, December 28, 2011 7:37 AM
  • I know I'm coming 3 years late to this party, but I've stumbled into this mud.   Can you post a code sample representing your solution.

    rhfritz

    Wednesday, March 20, 2013 3:45 PM
  • I've searched the above link for both CppNPS & NPC and surmise that these examples have moved somewhere else.  Can you provide an alternate link?  Thanks.


    rhfritz

    I found it @ code.msdn.microsoft.com

    

    • Edited by rhfritz Wednesday, March 20, 2013 4:49 PM
    Wednesday, March 20, 2013 3:50 PM
  • http://code.msdn.microsoft.com/windowsdesktop/site/search?f%5B0%5D.Type=Technology&f%5B0%5D.Value=IPC%20and%20RPC&f%5B0%5D.Text=IPC%20and%20RPC


    Visual C++ MVP

    • Proposed as answer by Com3t Sunday, May 05, 2013 8:23 AM
    Wednesday, March 20, 2013 11:04 PM
  • Is there any way you can post the exact code for setting up the SACL?
    Wednesday, July 23, 2014 5:45 PM
  • I followed the example code above.   But I found that the deployed solution under win7 had issues in a domain environment.   If my application was running as a service, non-privileged users couldn't interact with the pipe.   When I get time I'm going to dump this approach in favor of communication over a socket.

    rhfritz

    • Proposed as answer by Buysse Erwin Wednesday, October 15, 2014 1:59 PM
    Thursday, July 24, 2014 10:18 AM
  • I did some research today because I had the same problem on Windows7. 
    I succeeded to change the default DACL after that the pipe is created . 
    So it is not necessary to give a new security descriptor when creating the pipe. 

    


    
    
    • Edited by Buysse Erwin Wednesday, October 15, 2014 2:11 PM could not add code to the post
    Wednesday, October 15, 2014 2:09 PM
  • Could you create a new thread and post your code there, and the link here?  I'd like a solution where the owner of the pipe can set the ACL for everyone to use.

    rhfritz


    • Edited by rhfritz Thursday, October 16, 2014 2:09 AM
    Thursday, October 16, 2014 2:08 AM
  • Here is the solution link

    https://support.microsoft.com/en-us/help/813414/how-to-create-an-anonymous-pipe-that-gives-access-to-everyone

    And I have done one sample Code 

    you only need to set security attributes during createNamedpipe call

    //Server Side Code

    #include <windows.h>  #include <stdio.h>  #include <tchar.h> #include <strsafe.h> #include <AccCtrl.h> #include <Aclapi.h> #define BUFSIZE 512   DWORD WINAPI InstanceThread(LPVOID);  VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);      static PSECURITY_DESCRIPTOR    psd; static PTOKEN_USER pTokenUser; static PACL    pACL; static BOOL    allocated; /** Displays an error and exits the process Input parameters: pszAPI: name of the Win32 function that returned an error. */  void DisplayError( WCHAR* pszAPI ) { LPVOID lpvMessageBuffer; FormatMessage(  FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,                     NULL, GetLastError(),                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),                     (LPTSTR)&lpvMessageBuffer, 0, NULL); //... now display this string wprintf( L"ERROR: API        = %s.\n", pszAPI); wprintf( L"       error code = %d.\n", GetLastError()); wprintf( L"       message    = %s.\n", (char *)lpvMessageBuffer); // Free the buffer allocated by the system LocalFree( lpvMessageBuffer ); ExitProcess( GetLastError() ); }   /** Obtains the SID of the user running this thread or process. Output parameters: ppSidUser: the SID of the current user, TRUE   | FALSE: could not obtain the user SID */  BOOL GetUserSid( PSID*  ppSidUser ) {     HANDLE      hToken;     DWORD       dwLength;     DWORD       cbName = 250;     DWORD       cbDomainName = 250;          if( !OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken) )     {         if( GetLastError() == ERROR_NO_TOKEN )         {             if( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken) )             {                 return FALSE;             }         }         else         {             return FALSE;         }     }     if( !GetTokenInformation( hToken,       // handle of the access token                               TokenUser,    // type of information to retrieve                               pTokenUser,   // address of retrieved information                                0,            // size of the information buffer                               &dwLength     // address of required buffer size                               ))     {         if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )         {             pTokenUser = (PTOKEN_USER) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength );             if( pTokenUser == NULL )             {                 return FALSE;             }         }         else         {             return FALSE;         }     }     if( !GetTokenInformation(   hToken,     // handle of the access token                                 TokenUser,  // type of information to retrieve                                 pTokenUser, // address of retrieved information                                  dwLength,   // size of the information buffer                                 &dwLength   // address of required buffer size                                 ))     {         HeapFree( GetProcessHeap(), 0, pTokenUser );         pTokenUser = NULL;         return FALSE;     }     *ppSidUser = pTokenUser->User.Sid;     return TRUE; } /** Builds security attributes that allows read-only access to everyone Input parameters: psa: security attributes to build Output parameters: TRUE | FALSE */  BOOL  BuildSecurityAttributes( SECURITY_ATTRIBUTES* psa ) {     DWORD dwAclSize;     PSID  pSidAnonymous = NULL; // Well-known AnonymousLogin SID     PSID  pSidOwner = NULL;          if( allocated ) return FALSE;     SID_IDENTIFIER_AUTHORITY siaAnonymous = SECURITY_NT_AUTHORITY;     SID_IDENTIFIER_AUTHORITY siaOwner = SECURITY_NT_AUTHORITY;          do     {         psd = (PSECURITY_DESCRIPTOR) HeapAlloc( GetProcessHeap(),                                                 HEAP_ZERO_MEMORY,                                                 SECURITY_DESCRIPTOR_MIN_LENGTH);         if( psd == NULL )          {             DisplayError( L"HeapAlloc" );             break;         }         if( !InitializeSecurityDescriptor( psd, SECURITY_DESCRIPTOR_REVISION) )         {             DisplayError( L"InitializeSecurityDescriptor" );             break;         }         // Build anonymous SID         AllocateAndInitializeSid( &siaAnonymous, 1,                                    SECURITY_ANONYMOUS_LOGON_RID,                                    0,0,0,0,0,0,0,                                   &pSidAnonymous                                 );         if( !GetUserSid( &pSidOwner ) )         {             return FALSE;         }         // Compute size of ACL         dwAclSize = sizeof(ACL) +                     2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +                     GetLengthSid( pSidAnonymous ) +                     GetLengthSid( pSidOwner );                pACL = (PACL)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAclSize );         if( pACL == NULL )          {             DisplayError( L"HeapAlloc" );             break;         }             InitializeAcl( pACL, dwAclSize, ACL_REVISION);                      if( !AddAccessAllowedAce( pACL,                                   ACL_REVISION,                                   GENERIC_ALL,                                   pSidOwner                                 ))          {             DisplayError( L"AddAccessAllowedAce" );             break;         }                           if( !AddAccessAllowedAce( pACL,                                   ACL_REVISION,                                   FILE_GENERIC_READ, //GENERIC_READ | GENERIC_WRITE,                                   pSidAnonymous                                 ) )          {             DisplayError( L"AddAccessAllowedAce" );             break;         }             if( !SetSecurityDescriptorDacl( psd, TRUE, pACL, FALSE) )         {             DisplayError( L"SetSecurityDescriptorDacl" );             break;         }                psa->nLength = sizeof(SECURITY_ATTRIBUTES);         psa->bInheritHandle = TRUE;         psa->lpSecurityDescriptor = psd;         allocated = TRUE;     }while(0);     if( pSidAnonymous )   FreeSid( pSidAnonymous );     //if( pSidOwner )       FreeSid( pSidOwner );          if( !allocated )     {         if( psd ) HeapFree( GetProcessHeap(), 0, psd );         if( pACL ) HeapFree( GetProcessHeap(), 0 , pACL );     }     return allocated; } int _tmain(int argc, _TCHAR* argv[]) {     BOOL   fConnected = FALSE;     DWORD  dwThreadId = 0;     HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;     LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");     psd = NULL; //initialize    pTokenUser = NULL;     pACL = NULL;     allocated = FALSE;     SECURITY_ATTRIBUTES     sa;       BuildSecurityAttributes( &sa ); // The main loop creates an instance of the named pipe and  // then waits for a client to connect to it. When the client  // connects, a thread is created to handle communications  // with that client, and this loop is free to wait for the // next client connect request. It is an infinite loop.      for (;;)     {        _tprintf( TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);       hPipe = CreateNamedPipe(            lpszPipename,             // pipe name            PIPE_ACCESS_DUPLEX,       // read/write access            PIPE_TYPE_MESSAGE |       // message type pipe            PIPE_READMODE_MESSAGE |   // message-read mode            PIPE_WAIT,                // blocking mode            PIPE_UNLIMITED_INSTANCES, // max. instances             BUFSIZE,                  // output buffer size            BUFSIZE,                  // input buffer size            0,                        // client time-out            &sa );                    // default security attribute        if (hPipe == INVALID_HANDLE_VALUE)        {           _tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());            return -1;       }         // Wait for the client to connect; if it succeeds,        // the function returns a nonzero value. If the function       // returns zero, GetLastError returns ERROR_PIPE_CONNECTED.          fConnected = ConnectNamedPipe(hPipe, NULL) ?           TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);          if (fConnected)        {           printf("Client connected, creating a processing thread.\n");                  // Create a thread for this client.           hThread = CreateThread(              NULL,              // no security attribute              0,                 // default stack size              InstanceThread,    // thread proc             (LPVOID) hPipe,    // thread parameter              0,                 // not suspended              &dwThreadId);      // returns thread ID           if (hThread == NULL)           {             _tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());              return -1;          }          else CloseHandle(hThread);         }        else          // The client could not connect, so close the pipe.           CloseHandle(hPipe);     }     //Cleanup      if( allocated )     {              if( psd ) HeapFree( GetProcessHeap(), 0, psd );         if( pACL ) HeapFree( GetProcessHeap(), 0 , pACL );         if( pTokenUser ) HeapFree( GetProcessHeap(), 0, pTokenUser );         allocated = FALSE;     }    return 0;  }    DWORD WINAPI InstanceThread(LPVOID lpvParam) // This routine is a thread processing function to read from and reply to a client // via the open pipe connection passed from the main loop. Note this allows // the main loop to continue executing, potentially creating more threads of // of this procedure to run concurrently, depending on the number of incoming // client connections. {     HANDLE hHeap      = GetProcessHeap();    TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));    TCHAR* pchReply   = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));    DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;     BOOL fSuccess = FALSE;    HANDLE hPipe  = NULL;    // Do some extra error checking since the app will keep running even if this    // thread fails.    if (lpvParam == NULL)    {        printf( "\nERROR - Pipe Server Failure:\n");        printf( "   InstanceThread got an unexpected NULL value in lpvParam.\n");        printf( "   InstanceThread exitting.\n");        if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);        if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);        return (DWORD)-1;    }    if (pchRequest == NULL)    {        printf( "\nERROR - Pipe Server Failure:\n");        printf( "   InstanceThread got an unexpected NULL heap allocation.\n");        printf( "   InstanceThread exitting.\n");        if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);        return (DWORD)-1;    }    if (pchReply == NULL)    {        printf( "\nERROR - Pipe Server Failure:\n");        printf( "   InstanceThread got an unexpected NULL heap allocation.\n");        printf( "   InstanceThread exitting.\n");        if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);        return (DWORD)-1;    }    // Print verbose messages. In production code, this should be for debugging only.    printf("InstanceThread created, receiving and processing messages.\n"); // The thread's parameter is a handle to a pipe object instance.       hPipe = (HANDLE) lpvParam;  // Loop until done reading    while (1)     {     // Read client requests from the pipe. This simplistic code only allows messages    // up to BUFSIZE characters in length.       fSuccess = ReadFile(           hPipe,        // handle to pipe           pchRequest,    // buffer to receive data           BUFSIZE*sizeof(TCHAR), // size of buffer           &cbBytesRead, // number of bytes read           NULL);        // not overlapped I/O        if (!fSuccess || cbBytesRead == 0)       {              if (GetLastError() == ERROR_BROKEN_PIPE)           {               _tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());            }           else           {               _tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());            }           break;       }    // Process the incoming message.       GetAnswerToRequest(pchRequest, pchReply, &cbReplyBytes);       // Write the reply to the pipe.        fSuccess = WriteFile(           hPipe,        // handle to pipe           pchReply,     // buffer to write from           cbReplyBytes, // number of bytes to write           &cbWritten,   // number of bytes written           NULL);        // not overlapped I/O        if (!fSuccess || cbReplyBytes != cbWritten)       {              _tprintf(TEXT("InstanceThread WriteFile failed, GLE=%d.\n"), GetLastError());            break;       }   } // Flush the pipe to allow the client to read the pipe's contents  // before disconnecting. Then disconnect the pipe, and close the  // handle to this pipe instance.       FlushFileBuffers(hPipe);     DisconnectNamedPipe(hPipe);     CloseHandle(hPipe);     HeapFree(hHeap, 0, pchRequest);    HeapFree(hHeap, 0, pchReply);    printf("InstanceThread exitting.\n");    return 1; } VOID GetAnswerToRequest( LPTSTR pchRequest,                           LPTSTR pchReply,                           LPDWORD pchBytes ) // This routine is a simple function to print the client request to the console // and populate the reply buffer with a default data string. This is where you // would put the actual client request processing code that runs in the context // of an instance thread. Keep in mind the main thread will continue to wait for // and receive other client connections while the instance thread is working. {     _tprintf( TEXT("Client Request String:\"%s\"\n"), pchRequest );     // Check the outgoing message to make sure it's not too long for the buffer.     if (FAILED(StringCchCopy( pchReply, BUFSIZE, TEXT("default answer from server") )))     {         *pchBytes = 0;         pchReply[0] = 0;         printf("StringCchCopy failed, no outgoing message.\n");         return;     }     *pchBytes = (lstrlen(pchReply)+1)*sizeof(TCHAR); }

    Client code

    #include <windows.h> 
    #include <stdio.h>
    #include <conio.h>
    #include <tchar.h>
    
    #define BUFSIZE 512
     
    int _tmain(int argc, TCHAR *argv[]) 
    { 
       HANDLE hPipe; 
       LPTSTR lpvMessage=TEXT("Default message from client."); 
       TCHAR  chBuf[BUFSIZE]; 
       BOOL   fSuccess = FALSE; 
       DWORD  cbRead, cbToWrite, cbWritten, dwMode; 
       LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 
    
       if( argc > 1 )
          lpvMessage = argv[1];
     
    // Try to open a named pipe; wait for it, if necessary. 
     
       while (1) 
       { 
          hPipe = CreateFile( 
             lpszPipename,   // pipe name 
             GENERIC_READ |  // read and write access 
             GENERIC_WRITE, 
             0,              // no sharing 
             NULL,           // default security attributes
             OPEN_EXISTING,  // opens existing pipe 
             0,              // default attributes 
             NULL);          // no template file 
     
       // Break if the pipe handle is valid. 
     
          if (hPipe != INVALID_HANDLE_VALUE) 
             break; 
     
          // Exit if an error other than ERROR_PIPE_BUSY occurs. 
     
          if (GetLastError() != ERROR_PIPE_BUSY) 
          {
             _tprintf( TEXT("Could not open pipe. GLE=%d\n"), GetLastError() ); 
             return -1;
          }
     
          // All pipe instances are busy, so wait for 20 seconds. 
     
          if ( ! WaitNamedPipe(lpszPipename, 20000)) 
          { 
             printf("Could not open pipe: 20 second wait timed out."); 
             return -1;
          } 
       } 
     
    // The pipe connected; change to message-read mode. 
     
       dwMode = PIPE_READMODE_MESSAGE; 
       fSuccess = SetNamedPipeHandleState( 
          hPipe,    // pipe handle 
          &dwMode,  // new pipe mode 
          NULL,     // don't set maximum bytes 
          NULL);    // don't set maximum time 
       if ( ! fSuccess) 
       {
          _tprintf( TEXT("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError() ); 
          return -1;
       }
     
    // Send a message to the pipe server. 
     
       cbToWrite = (lstrlen(lpvMessage)+1)*sizeof(TCHAR);
       _tprintf( TEXT("Sending %d byte message: \"%s\"\n"), cbToWrite, lpvMessage); 
    
       fSuccess = WriteFile( 
          hPipe,                  // pipe handle 
          lpvMessage,             // message 
          cbToWrite,              // message length 
          &cbWritten,             // bytes written 
          NULL);                  // not overlapped 
    
       if ( ! fSuccess) 
       {
          _tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError() ); 
          return -1;
       }
    
       printf("\nMessage sent to server, receiving reply as follows:\n");
     
       do 
       { 
       // Read from the pipe. 
     
          fSuccess = ReadFile( 
             hPipe,    // pipe handle 
             chBuf,    // buffer to receive reply 
             BUFSIZE*sizeof(TCHAR),  // size of buffer 
             &cbRead,  // number of bytes read 
             NULL);    // not overlapped 
     
          if ( ! fSuccess && GetLastError() != ERROR_MORE_DATA )
             break; 
     
          _tprintf( TEXT("\"%s\"\n"), chBuf ); 
       } while ( ! fSuccess);  // repeat loop if ERROR_MORE_DATA 
    
       if ( ! fSuccess)
       {
          _tprintf( TEXT("ReadFile from pipe failed. GLE=%d\n"), GetLastError() );
          return -1;
       }
    
       printf("\n<End of message, press ENTER to terminate connection and exit>");
       _getch();
     
       CloseHandle(hPipe); 
     
       return 0; 
    }
    


    • Edited by Manish Karma Tuesday, March 07, 2017 8:34 AM Added client code
    • Proposed as answer by Manish Karma Tuesday, March 07, 2017 8:35 AM
    Tuesday, March 07, 2017 8:30 AM