1// The UnixCredentials system call is currently only implemented on Linux
2// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
3// https://golang.org/s/go1.4-syscall
4// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys
5
6// Local implementation of the UnixCredentials system call for FreeBSD
7
8package dbus
9
10/*
11const int sizeofPtr = sizeof(void*);
12#define _WANT_UCRED
13#include <sys/ucred.h>
14*/
15import "C"
16
17import (
18	"io"
19	"os"
20	"syscall"
21	"unsafe"
22)
23
24// http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go
25// https://golang.org/src/syscall/ztypes_freebsd_amd64.go
26type Ucred struct {
27	Pid int32
28	Uid uint32
29	Gid uint32
30}
31
32// http://golang.org/src/pkg/syscall/types_linux.go
33// https://golang.org/src/syscall/types_freebsd.go
34// https://github.com/freebsd/freebsd/blob/master/sys/sys/ucred.h
35const (
36	SizeofUcred = C.sizeof_struct_ucred
37)
38
39// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
40func cmsgAlignOf(salen int) int {
41	salign := C.sizeofPtr
42
43	return (salen + salign - 1) & ^(salign - 1)
44}
45
46// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
47func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer {
48	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr)))
49}
50
51// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
52// UnixCredentials encodes credentials into a socket control message
53// for sending to another process. This can be used for
54// authentication.
55func UnixCredentials(ucred *Ucred) []byte {
56	b := make([]byte, syscall.CmsgSpace(SizeofUcred))
57	h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
58	h.Level = syscall.SOL_SOCKET
59	h.Type = syscall.SCM_CREDS
60	h.SetLen(syscall.CmsgLen(SizeofUcred))
61	*((*Ucred)(cmsgData(h))) = *ucred
62	return b
63}
64
65// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
66// ParseUnixCredentials decodes a socket control message that contains
67// credentials in a Ucred structure. To receive such a message, the
68// SO_PASSCRED option must be enabled on the socket.
69func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) {
70	if m.Header.Level != syscall.SOL_SOCKET {
71		return nil, syscall.EINVAL
72	}
73	if m.Header.Type != syscall.SCM_CREDS {
74		return nil, syscall.EINVAL
75	}
76	ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
77	return &ucred, nil
78}
79
80func (t *unixTransport) SendNullByte() error {
81	ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
82	b := UnixCredentials(ucred)
83	_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
84	if err != nil {
85		return err
86	}
87	if oobn != len(b) {
88		return io.ErrShortWrite
89	}
90	return nil
91}
92