blob: 710e62549787823768a7365efe0a549bd15a837f [file] [log] [blame]
// +build !darwin
package dbus
import (
"errors"
"io"
"os"
"syscall"
)
func (t *unixTransport) SendNullByte() error {
ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
b := syscall.UnixCredentials(ucred)
_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
if err != nil {
return err
}
if oobn != len(b) {
return io.ErrShortWrite
}
return nil
}
func readMsg(file *os.File, p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
for {
n, oobn, flags, sa, err = syscall.Recvmsg(int(file.Fd()), p, oob, 0)
if err != nil {
if err == syscall.EAGAIN {
continue
}
}
break
}
return
}
func (t *unixTransport) ReadNullByte() error {
var oobBuf [4096]byte
res := []byte{0}
// There is currently no way to get at the underlying fd of a UnixConn, so
// we can't set SO_PASSCRED on it. We can use File() to get a copy of it though.
// Unfortunately that will not allow us to ReadMsgUnix, so we have to do that
// manually
file, err := t.File()
if err != nil {
return err
}
err = syscall.SetsockoptInt(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1)
if err != nil {
return err
}
n, oobn, flags, _, err := readMsg(file, res, oobBuf[:])
if err != nil {
return err
}
if n == 0 {
return io.ErrUnexpectedEOF
}
if flags&syscall.MSG_CTRUNC != 0 {
return errors.New("dbus: control data truncated")
}
msgs, err := syscall.ParseSocketControlMessage(oobBuf[:oobn])
if err != nil {
return err
}
for _, msg := range msgs {
cred, _ := syscall.ParseUnixCredentials(&msg)
if cred != nil {
t.hasPeerUid = true
t.peerUid = cred.Uid
}
}
return nil
}