summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Harris <pharris@opentext.com>2011-02-15 14:40:32 -0500
committerPeter Harris <pharris@opentext.com>2011-02-15 14:40:32 -0500
commitfd93ba09f760a785337bbed4cc0a79348dc6f451 (patch)
treeab8d68fe44abcf0acd3c36d1191e287b3b28a8ba
parentf8704f0486606a0d16fb1dbe28b6a8bc7ff425b0 (diff)
Add Auth support
MIT-MAGIC-COOKIE only so far. The XDM auth is considerably more complex.
-rw-r--r--Makefile1
-rw-r--r--xgob.go186
2 files changed, 180 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index 683737b..21a55a9 100644
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,7 @@
all: test noop xlsclients
# Dependencies
+xgob.6: xau.6
xgob/util/atom.6: xgob/xproto.6 xgob.6
xgob/xproto.6: xgob.6
xmu.6: xgob/util/atom.6 xgob/xproto.6 xgob.6
diff --git a/xgob.go b/xgob.go
index eda3a1c..223fcaf 100644
--- a/xgob.go
+++ b/xgob.go
@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"sync"
+ "xau"
)
const X_TCP_PORT = 6000
@@ -18,6 +19,14 @@ const (
MSBFirst = iota
)
+const (
+ FamilyInternet uint16 = 0
+ FamilyDECNet = 1
+ FamilyCHAOS = 2
+ FamilyServerInterpreted = 5
+ FamilyInternet6 = 6
+)
+
type Format struct {
Depth, BitsPerPixel, ScanlinePad uint8
}
@@ -216,7 +225,7 @@ func Pad(i int) int {
return (-i) & 3
}
-func (c *Connection) write_setup(name string, data string) {
+func (c *Connection) write_setup(name string, data []byte) {
buf := make([]byte, 0, 100)
buf = append(buf, 'B') // Big endian.
@@ -233,8 +242,7 @@ func (c *Connection) write_setup(name string, data string) {
for i := 0; i < Pad(len(name)); i++ {
buf = append(buf, 0)
}
- n = bytes.NewBufferString(data)
- buf = append(buf, n.Bytes()...)
+ buf = append(buf, data...)
for i := 0; i < Pad(len(data)); i++ {
buf = append(buf, 0)
}
@@ -503,7 +511,7 @@ func (c *Connection) read(in *bufio.Reader) {
}
}
-func (c *Connection) connect_auth(name string, data string) {
+func (c *Connection) connect_auth(name string, data []byte) {
c.write_setup(name, data)
in := bufio.NewReader(c.conn)
if !c.read_setup(in) {
@@ -518,7 +526,160 @@ func (c *Connection) connect_auth(name string, data string) {
go c.read(in)
}
-func Connect(dpy string) (conn *Connection, screen int) {
+type AuthInfo struct {
+ Name string
+ Data []byte
+}
+
+// AUTH starts
+
+const authXDM = "XDM-AUTHORIZATION-1"
+const authCookie = "MIT-MAGIC-COOKIE-1"
+
+type addresser interface {
+ LocalAddr() net.Addr
+ RemoteAddr() net.Addr
+}
+
+func getAuthPtr(a net.Addr, display int) *xau.Xauth {
+ family := xau.FamilyLocal
+ addr := []byte{0, 0, 0, 0}
+
+ switch a.Network() {
+ case "unix":
+ if name, err := os.Hostname(); err == nil {
+ addr = []byte(name)
+ }
+ case "tcp", "tcp4", "tcp6":
+ if tcp, ok := a.(*net.TCPAddr); ok {
+ ip4 := tcp.IP.To4()
+ if ip4 != nil {
+ addr = []byte(ip4)
+ if addr[0] == 127 {
+ // Loopback - use FamilyLocal
+ if name, err := os.Hostname(); err == nil {
+ addr = []byte(name)
+ }
+ } else {
+ family = FamilyInternet
+ }
+ } else {
+ ip6 := tcp.IP.To16()
+ if ip6 != nil {
+ addr = []byte(tcp.IP)
+ if bytes.Equal(addr, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) {
+ // Loopback - use FamilyLocal
+ if name, err := os.Hostname(); err == nil {
+ addr = []byte(name)
+ }
+ } else {
+ family = FamilyInternet6
+ }
+ } else {
+ return nil
+ }
+ }
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+
+ disp := []byte(strconv.Itoa(display))
+ return xau.GetBestAuthByAddr(family, addr, disp, []string{ /*authXDM,*/ authCookie})
+}
+
+func appendUint32(buf []byte, val uint32) []byte {
+ buf = append(buf, byte(val>>32))
+ buf = append(buf, byte(val>>24))
+ buf = append(buf, byte(val>>8))
+ buf = append(buf, byte(val&0xFF))
+ return buf
+}
+
+func computeAuth(auth *xau.Xauth, sockaddr net.Addr) *AuthInfo {
+ switch auth.Name {
+ case authCookie:
+ return &AuthInfo{auth.Name, auth.Data}
+ case authXDM:
+ var info AuthInfo
+ info.Data = make([]byte, 8, 192/8)
+ copy(info.Data, auth.Data)
+ switch sockaddr.Network() {
+ case "tcp", "tcp4", "tcp6":
+ if tcp, ok := sockaddr.(*net.TCPAddr); ok {
+ if ip4 := tcp.IP.To4(); ip4 != nil {
+ info.Data = append(info.Data, []byte(ip4)...)
+ info.Data = append(info.Data, byte(tcp.Port>>8))
+ info.Data = append(info.Data, byte(tcp.Port&0xFF))
+ } else if ip6 := tcp.IP.To16(); ip6 != nil {
+ /* XDM-AUTHORIZATION-1 does not handle IPv6 correctly. Do the
+ same thing Xlib does: use all zeroes for the 4-byte address
+ and 2-byte port number. */
+ info.Data = append(info.Data, 0, 0, 0, 0, 0, 0)
+ }
+ }
+ case "unix":
+ info.Data = appendUint32(info.Data, 0xFFFFFFFF) // TODO: -next_nonce()
+ pid := os.Getpid()
+ info.Data = append(info.Data, byte(pid>>8))
+ info.Data = append(info.Data, byte(pid&0xFF))
+ default:
+ return nil
+ }
+ time, _, _ := os.Time()
+ info.Data = appendUint32(info.Data, uint32(time))
+ for len(info.Data) < 192/8 {
+ info.Data = append(info.Data, 0)
+ }
+ panic("TODO: XdmcpWrap")
+ }
+ return nil
+}
+
+func (c *Connection) getAuthInfo(display int) *AuthInfo {
+ // code adapted from libXCB/xcb_auth.c
+ addr, ok := c.conn.(addresser)
+ if !ok {
+ return nil
+ }
+
+ var gotsockname bool
+ /* Some systems like hpux or Hurd do not expose peer names
+ * for UNIX Domain Sockets, but this is irrelevant,
+ * since compute_auth() ignores the peer name in this
+ * case anyway.*/
+ a := addr.RemoteAddr()
+ if a.String() == "" {
+ a = addr.LocalAddr()
+ if a.String() == "" {
+ return nil
+ }
+ if a.Network() != "unix" {
+ return nil
+ }
+ gotsockname = true
+ }
+
+ auth := getAuthPtr(a, display)
+ if auth == nil {
+ return nil
+ }
+
+ if !gotsockname {
+ a = addr.LocalAddr()
+ if a.String() == "" {
+ return nil
+ }
+ }
+
+ return computeAuth(auth, a)
+}
+
+// AUTH ends
+
+func ConnectWithAuth(dpy string, info *AuthInfo) (conn *Connection, screen int) {
host, proto, display, screen := parse_display(dpy)
var c Connection
@@ -528,13 +689,24 @@ func Connect(dpy string) (conn *Connection, screen int) {
return
}
- // TODO: name, data := c.get_auth_info()
- name, data := "", ""
+ var name string
+ data := make([]byte, 0)
+ if info == nil {
+ info = c.getAuthInfo(display)
+ }
+ if info != nil {
+ name = info.Name
+ data = info.Data
+ }
c.connect_auth(name, data)
conn = &c
return
}
+func Connect(dpy string) (conn *Connection, screen int) {
+ return ConnectWithAuth(dpy, nil)
+}
+
func (c *Connection) Disconnect() {
c.conn.Close()
c.conn = nil