title: c++: Let user process write to LOCAL_SYSTEM named pipe - Custom Security Descriptor
body: <p>I have a service running as <em>LocalSystem</em> which creates a Processes in the logged on users' session.
  Then the service creates a named pipe to which the client connects to read and write.
  According to <a href="https://msdn.microsoft.com/en-us/library/aa365600%28v=vs.85%29.aspx" rel="noreferrer">https://msdn.microsoft.com/en-us/library/aa365600%28v=vs.85%29.aspx</a> the client can only read from the pipe (It's No Admin, not the Creator, neither LocalSystem ).</p>
  
  <p>I created a security descriptor to grant the user read &amp; write access. But this didn't work. So i tried giving read &amp; write-access to the <em>Everyone</em>-Group. But this also does not work.
  The error code my client returns is always ACCESS_DENIED (5).</p>
  
  <p>I would be glad to know what i am doing wrong.</p>
  
  <p><strong>EDIT:</strong> if i don't create a custom security descriptor and just open the pipe with <code>GENERIC_READ</code> it works (but only reading).</p>
  
  <p><strong>EDIT2</strong> I want to learn how to do this right. And i still want to be only the logged on user able to write. Not everyone (this was just for testing).</p>
  
  <p>Service-Code (commented-out my code for getting the user sid):</p>
  
  <pre><code>PSID EveryoneSID                      = nullptr;
          SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
          if(!AllocateAndInitializeSid(&amp;SIDAuthWorld, 1,
                                   SECURITY_WORLD_RID,
                                   0, 0, 0, 0, 0, 0, 0,
                                   &amp;EveryoneSID))
          {
              throw(std::runtime_error("Failed to initialize group sid: " + std::to_string(GetLastError())));
          }
  
          //TOKEN_USER* tokeninfo     = nullptr;
          //DWORD tokeninfolen        = 0;
          //DWORD outlen              = 0;
          //// Query token info size
          //if(!GetTokenInformation(UserToken,
          //                  TokenUser,
          //                  tokeninfo,
          //                  tokeninfolen,
          //                  &amp;outlen))
          //{
          //  throw(std::runtime_error("Failed to obtain user token size: " + std::to_string(GetLastError())));
          //}
          //// Allocate enough space to hold token user information
          //tokeninfo    = (TOKEN_USER*) LocalAlloc(LPTR, outlen);
          //tokeninfolen = outlen;
  
          //// Get SID from user token
          //if(!GetTokenInformation(UserToken,
          //                  TokenUser,
          //                  tokeninfo,
          //                  tokeninfolen,
          //                  &amp;outlen))
          //{
          //  throw(std::runtime_error("Failed to obtain user token info: " + std::to_string(GetLastError())));
          //}
  
          //auto UserSID = tokeninfo-&gt;User.Sid;
          //LocalFree(tokeninfo);
  
          SECURITY_ATTRIBUTES sa = {0};
          ZeroMemory(&amp;sa, sizeof(SECURITY_ATTRIBUTES));
          sa.nLength = sizeof(SECURITY_ATTRIBUTES);
          sa.bInheritHandle = FALSE;
  
          // Set up ACE
          EXPLICIT_ACCESS ace      = {0};
          ace.grfAccessMode        = SET_ACCESS;
          ace.grfAccessPermissions = PIPE_ACCESS_DUPLEX;  // GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE
          ace.grfInheritance       = NO_INHERITANCE;
          ace.Trustee.TrusteeForm  = TRUSTEE_IS_SID;
          ace.Trustee.TrusteeType  = TRUSTEE_IS_WELL_KNOWN_GROUP;
          ace.Trustee.ptstrName    = (LPTSTR) EveryoneSID;
  
          PACL acl = nullptr;
          if(ERROR_SUCCESS != SetEntriesInAcl(1, &amp;ace, nullptr, &amp;acl))
              throw(std::runtime_error("Failed to set acl entries: " + std::to_string(GetLastError())));
  
          // Create security descriptor.
          auto sd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
          if(!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))
              throw(std::runtime_error("Failed to initialize security descriptor: " + std::to_string(GetLastError())));
          if(!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE))
              throw(std::runtime_error("Failed to set DACL: " + std::to_string(GetLastError())));
  
          // Set security descriptor in security attributes
          sa.lpSecurityDescriptor = sd;
  
          // Create a named pipe to which the user-session application
          // connects.
          auto pipe = CreateNamedPipe(LOCAL_PIPE_NAME,
                           PIPE_ACCESS_DUPLEX,
                           PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS | PIPE_WAIT,
                           1,
                           256,
                           256,
                           NULL,
                           &amp;sa);
          if(pipe == INVALID_HANDLE_VALUE)
              throw std::runtime_error("Failed to create named pipe");
  
          LocalFree(acl);
          LocalFree(sd);
  </code></pre>
  
  <p>User-Process-Code:</p>
  
  <pre><code>auto pipe = CreateFile(LOCAL_PIPE_NAME,
                             GENERIC_READ | GENERIC_WRITE,    // read access 
                              0,              // no sharing 
                              NULL,           // default security attributes
                              OPEN_EXISTING,  // opens existing pipe 
                              0,              // default attributes 
                              NULL);          // no template file 
      if (pipe == INVALID_HANDLE_VALUE)
          throw(std::runtime_error("Failed to open local pipe: " + std::to_string(GetLastError())));
  </code></pre>