Skip to content

Commit

Permalink
Add support for Solaris peer credentials.
Browse files Browse the repository at this point in the history
This refactors the test code for linux somewhat.  Also we added the
Solaris Zone ID, which matches what we do for NNG.  This works for
both Solaris and illumos targets, but only when cgo is enabled.
  • Loading branch information
gdamore committed Sep 27, 2020
1 parent 108b944 commit e0b0da2
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 50 deletions.
17 changes: 12 additions & 5 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,23 @@ const (

// OptionPeerPID is the peer process ID. This is only implemented for
// transports that support it, and it is a read-only option for pipes
// only. The value is an int.
// only. It may require cgo on some platforms. The value is an int.
OptionPeerPID = "PEER-PID"

// OptionPeerUID is the peer process user ID, typically obtained via
// OptionPeerUID is the effective peer user ID, typically obtained via
// SO_PEERCRED. It is only available transports that support it, and is
// a read-only option for pipes. The value of is an int.
// a read-only option for pipes. It may require cgo on some platforms.
// The value is an int.
OptionPeerUID = "PEER-UID"

// OptionPeerGID is the peer process group ID, typically obtained via
// OptionPeerGID is the effective peer group ID, typically obtained via
// SO_PEERCRED. It is only available transports that support it, and is
// a read-only option for pipes. The value of is an int.
// a read-only option for pipes. It may require cgo on some platforms.
// The value is an int.
OptionPeerGID = "PEER-GID"

// OptionPeerZone is the peer's zone ID. This is only supported on
// Solaris platforms at present, and only when cgo support is enabled.
// The value is an int.
OptionPeerZone = "PEER-ZONE"
)
2 changes: 0 additions & 2 deletions transport/ipc/ipc_peer_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// Package ipc implements the IPC transport on top of UNIX domain sockets.
// To enable it simply import it.
package ipc

import (
Expand Down
62 changes: 62 additions & 0 deletions transport/ipc/ipc_peer_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2020 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build linux

package ipc

import (
"os"
"testing"
"time"

"go.nanomsg.org/mangos/v3"
. "go.nanomsg.org/mangos/v3/internal/test"
)

func TestIpcPeerIdLinux(t *testing.T) {
sock1 := GetMockSocket()
sock2 := GetMockSocket()
defer MustClose(t, sock1)
defer MustClose(t, sock2)
addr := AddrTestIPC()
l, e := sock1.NewListener(addr, nil)
MustSucceed(t, e)
MustSucceed(t, l.Listen())
d, e := sock2.NewDialer(addr, nil)
MustSucceed(t, d.Dial())
time.Sleep(time.Millisecond * 20)

MustSend(t, sock1, make([]byte, 1))
m := MustRecvMsg(t, sock2)
p := m.Pipe

v, err := p.GetOption(mangos.OptionPeerPID)
MustSucceed(t, err)
pid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, pid == os.Getpid())

v, err = p.GetOption(mangos.OptionPeerUID)
MustSucceed(t, err)
uid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, uid == os.Getuid())

v, err = p.GetOption(mangos.OptionPeerGID)
MustSucceed(t, err)
gid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, gid == os.Getgid())
}
66 changes: 66 additions & 0 deletions transport/ipc/ipc_peer_solaris.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// +build solaris,cgo

// Copyright 2020 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ipc

import (
"net"

"go.nanomsg.org/mangos/v3"
"go.nanomsg.org/mangos/v3/transport"
)

// #include <ucred.h>
// #include <stdio.h>
// #include <zone.h>
// typedef struct mycred {
// pid_t pid;
// uid_t uid;
// gid_t gid;
// zoneid_t zid;
// } mycred_t;
// int getucred(int fd, mycred_t *mc)
// {
// ucred_t *uc = NULL;
// if ((getpeerucred(fd, &uc)) != 0) {
// return (-1);
// }
// mc->pid = ucred_getpid(uc);
// mc->uid = ucred_geteuid(uc);
// mc->gid = ucred_getegid(uc);
// mc->zid = ucred_getzoneid(uc);
// ucred_free(uc);
//
// return (0);
// }
import "C"

func getPeer(c *net.UnixConn, pipe transport.ConnPipe) {
if f, err := c.File(); err == nil {
mc := &C.mycred_t{}
if C.getucred(C.int(f.Fd()), mc) == 0 {
pipe.SetOption(mangos.OptionPeerPID, int(mc.pid))
pipe.SetOption(mangos.OptionPeerUID, int(mc.uid))
pipe.SetOption(mangos.OptionPeerGID, int(mc.gid))
pipe.SetOption(mangos.OptionPeerZone, int(mc.zid))
}
}
}

// getZone exists to support testing.
func getZone() int {
return int(C.getzoneid())
}
68 changes: 68 additions & 0 deletions transport/ipc/ipc_peer_solaris_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2020 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build solaris,cgo

package ipc

import (
"os"
"testing"
"time"

"go.nanomsg.org/mangos/v3"
. "go.nanomsg.org/mangos/v3/internal/test"
)

func TestIpcPeerIdSolaris(t *testing.T) {
sock1 := GetMockSocket()
sock2 := GetMockSocket()
defer MustClose(t, sock1)
defer MustClose(t, sock2)
addr := AddrTestIPC()
l, e := sock1.NewListener(addr, nil)
MustSucceed(t, e)
MustSucceed(t, l.Listen())
d, e := sock2.NewDialer(addr, nil)
MustSucceed(t, d.Dial())
time.Sleep(time.Millisecond * 20)

MustSend(t, sock1, make([]byte, 1))
m := MustRecvMsg(t, sock2)
p := m.Pipe

v, err := p.GetOption(mangos.OptionPeerPID)
MustSucceed(t, err)
pid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, pid == os.Getpid())

v, err = p.GetOption(mangos.OptionPeerUID)
MustSucceed(t, err)
uid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, uid == os.Getuid())

v, err = p.GetOption(mangos.OptionPeerGID)
MustSucceed(t, err)
gid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, gid == os.Getgid())

v, err = p.GetOption(mangos.OptionPeerZone)
MustSucceed(t, err)
zid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, zid == getZone())
}
2 changes: 1 addition & 1 deletion transport/ipc/ipc_peer_unix.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build !linux,!windows,!plan9,!js
// +build !linux,!windows,!plan9,!js,!solaris solaris,!cgo

// Copyright 2020 The Mangos Authors
//
Expand Down
43 changes: 1 addition & 42 deletions transport/ipc/ipc_unix_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019 The Mangos Authors
// Copyright 2020 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
Expand All @@ -20,7 +20,6 @@ import (
"errors"
"net"
"os"
"runtime"
"syscall"
"testing"
"time"
Expand Down Expand Up @@ -185,43 +184,3 @@ func TestIpcSendAbort(t *testing.T) {
time.Sleep(time.Millisecond * 100)
MustSucceed(t, c.Close())
}

func TestIpcPeerId(t *testing.T) {
sock1 := GetMockSocket()
sock2 := GetMockSocket()
defer MustClose(t, sock1)
defer MustClose(t, sock2)
addr := AddrTestIPC()
l, e := sock1.NewListener(addr, nil)
MustSucceed(t, e)
MustSucceed(t, l.Listen())
d, e := sock2.NewDialer(addr, nil)
MustSucceed(t, d.Dial())
time.Sleep(time.Millisecond*20)

MustSend(t, sock1, make([]byte, 1))
m := MustRecvMsg(t, sock2)
p := m.Pipe

switch runtime.GOOS {
case "linux":
v, err := p.GetOption(mangos.OptionPeerPID)
MustSucceed(t, err)
pid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, pid == os.Getpid())

v, err = p.GetOption(mangos.OptionPeerUID)
MustSucceed(t, err)
uid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, uid == os.Getuid())

v, err = p.GetOption(mangos.OptionPeerGID)
MustSucceed(t, err)
gid, ok := v.(int)
MustBeTrue(t, ok)
MustBeTrue(t, gid == os.Getgid())
default:
}
}

0 comments on commit e0b0da2

Please sign in to comment.