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