diff --git a/go.mod b/go.mod index 2154c3f..564acb6 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module inet.af/peercred go 1.14 -require golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65 +require golang.org/x/sys v0.0.0-20210216224549-f992740a1bac diff --git a/go.sum b/go.sum index 5f07646..c10d96d 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65 h1:pTMjDVnP5eVRRlWO76rEWJ8JoC6Lf1CmyjPZXRiy2Sw= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216224549-f992740a1bac h1:9glrpwtNjBYgRpb67AZJKHfzj1stG/8BL5H7In2oTC4= +golang.org/x/sys v0.0.0-20210216224549-f992740a1bac/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/peercred_darwin.go b/peercred_darwin.go new file mode 100644 index 0000000..f483b6d --- /dev/null +++ b/peercred_darwin.go @@ -0,0 +1,62 @@ +// Copyright (c) 2021 AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package peercred + +import ( + "fmt" + "net" + "strconv" + + "golang.org/x/sys/unix" +) + +func init() { + osGet = getLinux +} + +func getLinux(c net.Conn) (*Creds, error) { + switch c := c.(type) { + case *net.UnixConn: + return getUnix(c) + case *net.TCPConn: + // TODO: use /proc tcp info for localhost connections like Windows? + } + return nil, ErrUnsupportedConnType +} + +func getUnix(c *net.UnixConn) (*Creds, error) { + raw, err := c.SyscallConn() + if err != nil { + return nil, fmt.Errorf("SyscallConn: %w", err) + } + + var cred *unix.Xucred + var pid int + cerr := raw.Control(func(fd uintptr) { + cred, err = unix.GetsockoptXucred(int(fd), + unix.SOL_LOCAL, + unix.LOCAL_PEERCRED) + if err != nil { + err = fmt.Errorf("unix.GetsockoptXucred: %w", err) + return + } + pid, err = unix.GetsockoptInt(int(fd), + unix.SOL_LOCAL, + unix.LOCAL_PEERPID) + if err != nil { + err = fmt.Errorf("unix.GetsockoptInt: %w", err) + } + }) + if cerr != nil { + return nil, fmt.Errorf("raw.Control: %w", err) + } + if err != nil { + return nil, err + } + return &Creds{ + pid: pid, + uid: strconv.FormatUint(uint64(cred.Uid), 10), + }, nil +} diff --git a/peercred_unix_test.go b/peercred_unix_test.go index cc5d894..0d98102 100644 --- a/peercred_unix_test.go +++ b/peercred_unix_test.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build go1.15 -// +build linux +// +build linux darwin package peercred // import "inet.af/peercred" @@ -15,7 +15,7 @@ import ( "testing" ) -func TestUnix(t *testing.T) { +func TestUnixSock(t *testing.T) { d := t.TempDir() path := filepath.Join(d, "foo.sock") sock, err := net.Listen("unix", path) @@ -24,14 +24,21 @@ func TestUnix(t *testing.T) { } defer sock.Close() + clientConnCh := make(chan net.Conn, 1) go func() { + defer close(clientConnCh) c, err := net.Dial("unix", path) if err != nil { t.Error(err) return } - c.Close() + clientConnCh <- c }() + clientConn, ok := <-clientConnCh + if !ok { + return + } + defer clientConn.Close() c, err := sock.Accept() if err != nil {