func RemoteRecvCredentials(conn *net.UnixConn) (uint32, uint32, error) { err := syscall.SetsockoptInt(sysfd(conn), syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) if err != nil { return 0, 0, err } oob := make([]byte, len(syscall.UnixCredentials(&syscall.Ucred{}))) _, _, _, _, err = conn.ReadMsgUnix(nil, oob) if err != nil { return 0, 0, err } scm, err := syscall.ParseSocketControlMessage(oob) if err != nil { return 0, 0, err } ucred, err := syscall.ParseUnixCredentials(&scm[0]) if err != nil { return 0, 0, err } return ucred.Uid, ucred.Gid, nil }
func (s *OOBUnixConn) Read(p []byte) (n int, err error) { var oob [OOBMaxLength]byte n, oobn, _, _, err := s.ReadMsgUnix(p, oob[:]) if err == nil && n > 0 && oobn > 0 { scm, err := syscall.ParseSocketControlMessage(oob[0:oobn]) if err != nil { return n, err } s.m.Lock() for _, m := range scm { if m.Header.Level != syscall.SOL_SOCKET { continue } switch m.Header.Type { case syscall.SCM_RIGHTS: if fds, err := syscall.ParseUnixRights(&m); err == nil { for _, fd := range fds { // Note: We wrap the raw FDs inside an os.File just // once, early, to prevent double-free or leaking FDs. f := NewFile(fd) s.recvFiles = append(s.recvFiles, f) } } case syscall.SCM_CREDENTIALS: if ucred, err := syscall.ParseUnixCredentials(&m); err == nil { s.peerCred = &Ucred{Uid: ucred.Uid, Gid: ucred.Gid} } } } s.m.Unlock() } return n, err }
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 }
func (m *Message) parseControlData(data []byte) error { cmsgs, err := syscall.ParseSocketControlMessage(data) if err != nil { return err } for _, cmsg := range cmsgs { switch cmsg.Header.Type { case syscall.SCM_CREDENTIALS: cred, err := syscall.ParseUnixCredentials(&cmsg) if err != nil { return err } m.Ucred = cred case syscall.SCM_RIGHTS: fds, err := syscall.ParseUnixRights(&cmsg) if err != nil { return err } m.Fds = fds } } return nil }
// TestSCMCredentials tests the sending and receiving of credentials // (PID, UID, GID) in an ancillary message between two UNIX // sockets. The SO_PASSCRED socket option is enabled on the sending // socket for this to work. func TestSCMCredentials(t *testing.T) { fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer syscall.Close(fds[0]) defer syscall.Close(fds[1]) err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) if err != nil { t.Fatalf("SetsockoptInt: %v", err) } srv, err := net.FileConn(os.NewFile(uintptr(fds[0]), "")) if err != nil { t.Errorf("FileConn: %v", err) return } defer srv.Close() cli, err := net.FileConn(os.NewFile(uintptr(fds[1]), "")) if err != nil { t.Errorf("FileConn: %v", err) return } defer cli.Close() var ucred syscall.Ucred if os.Getuid() != 0 { ucred.Pid = int32(os.Getpid()) ucred.Uid = 0 ucred.Gid = 0 oob := syscall.UnixCredentials(&ucred) _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err.(*net.OpError).Err != syscall.EPERM { t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) } } ucred.Pid = int32(os.Getpid()) ucred.Uid = uint32(os.Getuid()) ucred.Gid = uint32(os.Getgid()) oob := syscall.UnixCredentials(&ucred) // this is going to send a dummy byte n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err != nil { t.Fatalf("WriteMsgUnix: %v", err) } if n != 0 { t.Fatalf("WriteMsgUnix n = %d, want 0", n) } if oobn != len(oob) { t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) } oob2 := make([]byte, 10*len(oob)) n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) if err != nil { t.Fatalf("ReadMsgUnix: %v", err) } if flags != 0 { t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) } if n != 1 { t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n) } if oobn2 != oobn { // without SO_PASSCRED set on the socket, ReadMsgUnix will // return zero oob bytes t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) } oob2 = oob2[:oobn2] if !bytes.Equal(oob, oob2) { t.Fatal("ReadMsgUnix oob bytes don't match") } scm, err := syscall.ParseSocketControlMessage(oob2) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } newUcred, err := syscall.ParseUnixCredentials(&scm[0]) if err != nil { t.Fatalf("ParseUnixCredentials: %v", err) } if *newUcred != ucred { t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) } }