mirror of
https://github.com/golang/go
synced 2024-11-25 06:07:58 -07:00
Add authentication.
Other code fixing: - Fixed bugs in get32. - Fix code for parsing display string (as a new function). - Fix code for connecting to X server. The old code only work if the server is listening to TCP port, otherwise it doesn't work (at least in my PC). R=nigeltao_golang, rsc, jhh CC=golang-dev https://golang.org/cl/183111
This commit is contained in:
parent
f43d95fbde
commit
9628d4c6eb
110
src/pkg/xgb/auth.go
Normal file
110
src/pkg/xgb/auth.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package xgb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getU16BE(r io.Reader, b []byte) (uint16, os.Error) {
|
||||||
|
_, err := io.ReadFull(r, b[0:2])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint16(b[0])<<8 + uint16(b[1]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBytes(r io.Reader, b []byte) ([]byte, os.Error) {
|
||||||
|
n, err := getU16BE(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if int(n) > len(b) {
|
||||||
|
return nil, os.NewError("bytes too long for buffer")
|
||||||
|
}
|
||||||
|
_, err = io.ReadFull(r, b[0:n])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b[0:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getString(r io.Reader, b []byte) (string, os.Error) {
|
||||||
|
b, err := getBytes(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readAuthority reads the X authority file for the DISPLAY.
|
||||||
|
// If hostname == "" or hostname == "localhost",
|
||||||
|
// readAuthority uses the system's hostname (as returned by os.Hostname) instead.
|
||||||
|
func readAuthority(hostname, display string) (name string, data []byte, err os.Error) {
|
||||||
|
// b is a scratch buffer to use and should be at least 256 bytes long
|
||||||
|
// (i.e. it should be able to hold a hostname).
|
||||||
|
var b [256]byte
|
||||||
|
|
||||||
|
// As per /usr/include/X11/Xauth.h.
|
||||||
|
const familyLocal = 256
|
||||||
|
|
||||||
|
if len(hostname) == 0 || hostname == "localhost" {
|
||||||
|
hostname, err = os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fname := os.Getenv("XAUTHORITY")
|
||||||
|
if len(fname) == 0 {
|
||||||
|
home := os.Getenv("HOME")
|
||||||
|
if len(home) == 0 {
|
||||||
|
err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set")
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
fname = home + "/.Xauthority"
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := os.Open(fname, os.O_RDONLY, 0444)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
br := bufio.NewReader(r)
|
||||||
|
for {
|
||||||
|
family, err := getU16BE(br, b[0:2])
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := getString(br, b[0:])
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
disp, err := getString(br, b[0:])
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name0, err := getString(br, b[0:])
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data0, err := getBytes(br, b[0:])
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if family == familyLocal && addr == hostname && disp == display {
|
||||||
|
return name0, data0, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
@ -18,12 +18,14 @@ import (
|
|||||||
// A Conn represents a connection to an X server.
|
// A Conn represents a connection to an X server.
|
||||||
// Only one goroutine should use a Conn's methods at a time.
|
// Only one goroutine should use a Conn's methods at a time.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
|
host string
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
nextId Id
|
nextId Id
|
||||||
nextCookie Cookie
|
nextCookie Cookie
|
||||||
replies map[Cookie][]byte
|
replies map[Cookie][]byte
|
||||||
events queue
|
events queue
|
||||||
err os.Error
|
err os.Error
|
||||||
|
display string
|
||||||
defaultScreen int
|
defaultScreen int
|
||||||
scratch [32]byte
|
scratch [32]byte
|
||||||
Setup SetupInfo
|
Setup SetupInfo
|
||||||
@ -89,7 +91,7 @@ func get32(buf []byte) uint32 {
|
|||||||
v := uint32(buf[0])
|
v := uint32(buf[0])
|
||||||
v |= uint32(buf[1]) << 8
|
v |= uint32(buf[1]) << 8
|
||||||
v |= uint32(buf[2]) << 16
|
v |= uint32(buf[2]) << 16
|
||||||
v |= uint32(buf[3]) << 32
|
v |= uint32(buf[3]) << 24
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,49 +286,39 @@ func (c *Conn) PollForEvent() (Event, os.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the X server given in the 'display' string.
|
// Dial connects to the X server given in the 'display' string.
|
||||||
// The display string is typically taken from os.Getenv("DISPLAY").
|
// If 'display' is empty it will be taken from os.Getenv("DISPLAY").
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// Dial(":1") // connect to net.Dial("unix", "", "/tmp/.X11-unix/X1")
|
||||||
|
// Dial("/tmp/launch-123/:0") // connect to net.Dial("unix", "", "/tmp/launch-123/:0")
|
||||||
|
// Dial("hostname:2.1") // connect to net.Dial("tcp", "", "hostname:6002")
|
||||||
|
// Dial("tcp/hostname:1.0") // connect to net.Dial("tcp", "", "hostname:6001")
|
||||||
func Dial(display string) (*Conn, os.Error) {
|
func Dial(display string) (*Conn, os.Error) {
|
||||||
var err os.Error
|
c, err := connect(display)
|
||||||
|
if err != nil {
|
||||||
c := new(Conn)
|
return nil, err
|
||||||
|
|
||||||
if display[0] == '/' {
|
|
||||||
c.conn, err = net.Dial("unix", "", display)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("cannot connect: %v\n", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parts := strings.Split(display, ":", 2)
|
|
||||||
host := parts[0]
|
|
||||||
port := 0
|
|
||||||
if len(parts) > 1 {
|
|
||||||
parts = strings.Split(parts[1], ".", 2)
|
|
||||||
port, _ = strconv.Atoi(parts[0])
|
|
||||||
if len(parts) > 1 {
|
|
||||||
c.defaultScreen, _ = strconv.Atoi(parts[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
display = fmt.Sprintf("%s:%d", host, port+6000)
|
|
||||||
c.conn, err = net.Dial("tcp", "", display)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("cannot connect: %v\n", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: get these from .Xauthority
|
// Get authentication data
|
||||||
var authName, authData []byte
|
authName, authData, err := readAuthority(c.host, c.display)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
|
||||||
|
if authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16 {
|
||||||
|
return nil, os.NewError("unsupported auth protocol " + authName)
|
||||||
|
}
|
||||||
|
|
||||||
buf := make([]byte, 12+pad(len(authName))+pad(len(authData)))
|
buf := make([]byte, 12+pad(len(authName))+pad(len(authData)))
|
||||||
buf[0] = 'l'
|
buf[0] = 0x6c
|
||||||
buf[1] = 0
|
buf[1] = 0
|
||||||
put16(buf[2:], 11)
|
put16(buf[2:], 11)
|
||||||
put16(buf[4:], 0)
|
put16(buf[4:], 0)
|
||||||
put16(buf[6:], uint16(len(authName)))
|
put16(buf[6:], uint16(len(authName)))
|
||||||
put16(buf[8:], uint16(len(authData)))
|
put16(buf[8:], uint16(len(authData)))
|
||||||
put16(buf[10:], 0)
|
put16(buf[10:], 0)
|
||||||
copy(buf[12:], authName)
|
copy(buf[12:], strings.Bytes(authName))
|
||||||
copy(buf[12+pad(len(authName)):], authData)
|
copy(buf[12+pad(len(authName)):], authData)
|
||||||
if _, err = c.conn.Write(buf); err != nil {
|
if _, err = c.conn.Write(buf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -396,3 +388,77 @@ func getClientMessageData(b []byte, v *ClientMessageData) int {
|
|||||||
}
|
}
|
||||||
return 20
|
return 20
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func connect(display string) (*Conn, os.Error) {
|
||||||
|
if len(display) == 0 {
|
||||||
|
display = os.Getenv("DISPLAY")
|
||||||
|
}
|
||||||
|
|
||||||
|
display0 := display
|
||||||
|
if len(display) == 0 {
|
||||||
|
return nil, os.NewError("empty display string")
|
||||||
|
}
|
||||||
|
|
||||||
|
colonIdx := strings.LastIndex(display, ":")
|
||||||
|
if colonIdx < 0 {
|
||||||
|
return nil, os.NewError("bad display string: " + display0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var protocol, socket string
|
||||||
|
c := new(Conn)
|
||||||
|
|
||||||
|
if display[0] == '/' {
|
||||||
|
socket = display[0:colonIdx]
|
||||||
|
} else {
|
||||||
|
slashIdx := strings.LastIndex(display, "/")
|
||||||
|
if slashIdx >= 0 {
|
||||||
|
protocol = display[0:slashIdx]
|
||||||
|
c.host = display[slashIdx+1 : colonIdx]
|
||||||
|
} else {
|
||||||
|
c.host = display[0:colonIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display = display[colonIdx+1 : len(display)]
|
||||||
|
if len(display) == 0 {
|
||||||
|
return nil, os.NewError("bad display string: " + display0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var scr string
|
||||||
|
dotIdx := strings.LastIndex(display, ".")
|
||||||
|
if dotIdx < 0 {
|
||||||
|
c.display = display[0:]
|
||||||
|
} else {
|
||||||
|
c.display = display[0:dotIdx]
|
||||||
|
scr = display[dotIdx+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
dispnum, err := strconv.Atoui(c.display)
|
||||||
|
if err != nil {
|
||||||
|
return nil, os.NewError("bad display string: " + display0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(scr) != 0 {
|
||||||
|
c.defaultScreen, err = strconv.Atoi(scr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, os.NewError("bad display string: " + display0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to server
|
||||||
|
if len(socket) != 0 {
|
||||||
|
c.conn, err = net.Dial("unix", "", socket+":"+c.display)
|
||||||
|
} else if len(c.host) != 0 {
|
||||||
|
if protocol == "" {
|
||||||
|
protocol = "tcp"
|
||||||
|
}
|
||||||
|
c.conn, err = net.Dial(protocol, "", c.host+":"+strconv.Uitoa(6000+dispnum))
|
||||||
|
} else {
|
||||||
|
c.conn, err = net.Dial("unix", "", "/tmp/.X11-unix/X"+c.display)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, os.NewError("cannot connect to " + display0 + ": " + err.String())
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user