@@ -24,12 +24,15 @@ import (
2424 "context"
2525 "fmt"
2626 "net"
27- "os/user"
2827 "strings"
28+ "syscall"
2929
30- winio "github.com/Microsoft/go-winio"
30+ "github.com/Microsoft/go-winio"
3131)
3232
33+ // ntAuthoritySystemSID is a well-known SID used by the NT AUTHORITY\SYSTEM account.
34+ const ntAuthoritySystemSID = "S-1-5-18"
35+
3336// NewListener creates a new Listener receiving events over a named pipe.
3437func NewListener (name , sd string ) (net.Listener , error ) {
3538 c := & winio.PipeConfig {
@@ -44,18 +47,14 @@ func NewListener(name, sd string) (net.Listener, error) {
4447 return l , nil
4548}
4649
47- // TransformString takes an input type name defined as a URI like `npipe:///hello` and transform it into
48- // `\\.\pipe\hello`
50+ // TransformString takes an input type name defined as a URI like
51+ // `npipe:///hello` and transforms it into // ` \\.\pipe\hello`
4952func TransformString (name string ) string {
5053 if strings .HasPrefix (name , "npipe:///" ) {
5154 path := strings .TrimPrefix (name , "npipe:///" )
5255 return `\\.\pipe\` + path
5356 }
5457
55- if strings .HasPrefix (name , `\\.\pipe\` ) {
56- return name
57- }
58-
5958 return name
6059}
6160
@@ -73,37 +72,70 @@ func Dial(npipe string) func(string, string) (net.Conn, error) {
7372 }
7473}
7574
76- // DefaultSD returns a default SecurityDescriptor which is the minimal required permissions to be
75+ // DefaultSD returns a default SecurityDescriptor that specifies the minimal required permissions to be
7776// able to write to the named pipe. The security descriptor is returned in SDDL format.
7877//
7978// Docs: https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
8079func DefaultSD (forUser string ) (string , error ) {
81- var u * user.User
82- var err error
83- // No user configured we fallback to the current running user.
84- if len (forUser ) == 0 {
85- u , err = user .Current ()
86- if err != nil {
87- return "" , fmt .Errorf ("failed to retrieve the current user: %w" , err )
88- }
89- } else {
90- u , err = user .Lookup (forUser )
91- if err != nil {
92- return "" , fmt .Errorf ("failed to retrieve the user %s: %w" , forUser , err )
93- }
80+ sid , err := lookupSID (forUser )
81+ if err != nil {
82+ return "" , err
9483 }
9584
9685 // Named pipe security and access rights.
9786 // We create the pipe and the specific users should only be able to write to it.
9887 // See docs: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-security-and-access-rights
9988 // String definition: https://docs.microsoft.com/en-us/windows/win32/secauthz/ace-strings
10089 // Give generic read/write access to the specified user.
101- descriptor := "D:P(A;;GA;;;" + u . Uid + ")"
102- if u . Username == "NT AUTHORITY \\ SYSTEM" {
90+ descriptor := "D:P(A;;GA;;;" + sid + ")"
91+ if sid == ntAuthoritySystemSID {
10392 // running as SYSTEM, include Administrators group so Administrators can talk over
10493 // the named pipe to the running Elastic Agent system process
10594 // https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
10695 descriptor += "(A;;GA;;;S-1-5-32-544)" // Administrators group
10796 }
10897 return descriptor , nil
10998}
99+
100+ // lookupSID returns the SID of the specified username. If username is empty the
101+ // SID of the current user is returned.
102+ func lookupSID (username string ) (string , error ) {
103+ if username == "" {
104+ sid , err := currentUserSID ()
105+ if err != nil {
106+ return "" , fmt .Errorf ("failed to lookup the SID of current user: %w" , err )
107+ }
108+ return sid , nil
109+ }
110+
111+ sid , _ , _ , err := syscall .LookupSID ("" , username )
112+ if err != nil {
113+ return "" , fmt .Errorf ("failed to lookup the SID for user %q: %w" , username , err )
114+ }
115+ sidString , err := sid .String ()
116+ if err != nil {
117+ return "" , fmt .Errorf ("failed to convert the SID for user %q to string: %w" , username , err )
118+ }
119+ return sidString , nil
120+ }
121+
122+ // currentUserSID returns the SID of the user running the current process.
123+ func currentUserSID () (string , error ) {
124+ t , err := syscall .OpenCurrentProcessToken ()
125+ if err != nil {
126+ return "" , err
127+ }
128+ defer t .Close ()
129+
130+ u , err := t .GetTokenUser ()
131+ if err != nil {
132+ return "" , err
133+ }
134+
135+ sid , err := u .User .Sid .String ()
136+ if err != nil {
137+ return "" , err
138+ }
139+
140+ return sid , nil
141+ }
0 commit comments