diff --git a/go.mod b/go.mod index 564acb6..d23b979 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-20210216224549-f992740a1bac +require golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b diff --git a/go.sum b/go.sum index c10d96d..977a1fe 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,5 @@ golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65 h1:pTMjDVnP5eVRRlWO76rEWJ8Jo 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= +golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b h1:kHlr0tATeLRMEiZJu5CknOw/E8V6h69sXXQFGoPtjcc= +golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/peercred_freebsd.go b/peercred_freebsd.go new file mode 100644 index 0000000..6b6b14d --- /dev/null +++ b/peercred_freebsd.go @@ -0,0 +1,55 @@ +// 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 = getFreeBSD +} + +func getFreeBSD(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 + 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 + } + }) + if cerr != nil { + return nil, fmt.Errorf("raw.Control: %w", err) + } + if err != nil { + return nil, err + } + return &Creds{ + pid: 0, // FreeBSD 13 adds a cr_pid field, can be used here. + uid: strconv.FormatUint(uint64(cred.Uid), 10), + }, nil +} diff --git a/peercred_unix_test.go b/peercred_unix_test.go index 0d98102..474deef 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 darwin +// +build linux darwin freebsd package peercred // import "inet.af/peercred" @@ -12,6 +12,7 @@ import ( "net" "os" "path/filepath" + "runtime" "testing" ) @@ -59,11 +60,16 @@ func TestUnixSock(t *testing.T) { t.Errorf("UID = %q; want %q", got, want) } pid, ok := creds.PID() - if !ok { - t.Errorf("no PID") + if runtime.GOOS == "freebsd" { + if ok { + t.Error("PID ok; want !ok. Thank you for fixing FreeBSD, please update the test.") + } + } else { + if !ok { + t.Errorf("no PID") + } + if got, want := pid, os.Getpid(); got != want { + t.Errorf("PID = %v; want %v", got, want) + } } - if got, want := pid, os.Getpid(); got != want { - t.Errorf("PID = %v; want %v", got, want) - } - }