1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 // TestSCMCredentials tests the sending and receiving of credentials
18 // (PID, UID, GID) in an ancillary message between two UNIX
19 // sockets. The SO_PASSCRED socket option is enabled on the sending
20 // socket for this to work.
21 func TestSCMCredentials(t
*testing
.T
) {
22 socketTypeTests
:= []struct {
35 for _
, tt
:= range socketTypeTests
{
36 fds
, err
:= syscall
.Socketpair(syscall
.AF_LOCAL
, tt
.socketType
, 0)
38 t
.Fatalf("Socketpair: %v", err
)
41 err
= syscall
.SetsockoptInt(fds
[0], syscall
.SOL_SOCKET
, syscall
.SO_PASSCRED
, 1)
45 t
.Fatalf("SetsockoptInt: %v", err
)
48 srvFile
:= os
.NewFile(uintptr(fds
[0]), "server")
49 cliFile
:= os
.NewFile(uintptr(fds
[1]), "client")
53 srv
, err
:= net
.FileConn(srvFile
)
55 t
.Errorf("FileConn: %v", err
)
60 cli
, err
:= net
.FileConn(cliFile
)
62 t
.Errorf("FileConn: %v", err
)
67 var ucred syscall
.Ucred
69 ucred
.Pid
= int32(os
.Getpid())
72 oob
:= syscall
.UnixCredentials(&ucred
)
73 _
, _
, err
:= cli
.(*net
.UnixConn
).WriteMsgUnix(nil, oob
, nil)
74 if op
, ok
:= err
.(*net
.OpError
); ok
{
77 if sys
, ok
:= err
.(*os
.SyscallError
); ok
{
80 if err
!= syscall
.EPERM
{
81 t
.Fatalf("WriteMsgUnix failed with %v, want EPERM", err
)
85 ucred
.Pid
= int32(os
.Getpid())
86 ucred
.Uid
= uint32(os
.Getuid())
87 ucred
.Gid
= uint32(os
.Getgid())
88 oob
:= syscall
.UnixCredentials(&ucred
)
90 // On SOCK_STREAM, this is internally going to send a dummy byte
91 n
, oobn
, err
:= cli
.(*net
.UnixConn
).WriteMsgUnix(nil, oob
, nil)
93 t
.Fatalf("WriteMsgUnix: %v", err
)
96 t
.Fatalf("WriteMsgUnix n = %d, want 0", n
)
99 t
.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn
, len(oob
))
102 oob2
:= make([]byte, 10*len(oob
))
103 n
, oobn2
, flags
, _
, err
:= srv
.(*net
.UnixConn
).ReadMsgUnix(nil, oob2
)
105 t
.Fatalf("ReadMsgUnix: %v", err
)
107 if flags
!= syscall
.MSG_CMSG_CLOEXEC
{
108 t
.Fatalf("ReadMsgUnix flags = %#x, want %#x (MSG_CMSG_CLOEXEC)", flags
, syscall
.MSG_CMSG_CLOEXEC
)
111 t
.Fatalf("ReadMsgUnix n = %d, want %d", n
, tt
.dataLen
)
114 // without SO_PASSCRED set on the socket, ReadMsgUnix will
115 // return zero oob bytes
116 t
.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2
, oobn
)
119 if !bytes
.Equal(oob
, oob2
) {
120 t
.Fatal("ReadMsgUnix oob bytes don't match")
123 scm
, err
:= syscall
.ParseSocketControlMessage(oob2
)
125 t
.Fatalf("ParseSocketControlMessage: %v", err
)
127 newUcred
, err
:= syscall
.ParseUnixCredentials(&scm
[0])
129 t
.Fatalf("ParseUnixCredentials: %v", err
)
131 if *newUcred
!= ucred
{
132 t
.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred
, ucred
)