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