Exemple #1
0
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
}
Exemple #4
0
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
}
Exemple #5
0
// 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)
	}
}