summaryrefslogtreecommitdiff
path: root/xau
diff options
context:
space:
mode:
Diffstat (limited to 'xau')
-rw-r--r--xau/xau.go200
1 files changed, 200 insertions, 0 deletions
diff --git a/xau/xau.go b/xau/xau.go
new file mode 100644
index 0000000..2f3ec9a
--- /dev/null
+++ b/xau/xau.go
@@ -0,0 +1,200 @@
+package xau
+
+import (
+ "bytes"
+ "io"
+ "os"
+)
+
+const (
+ FamilyLocal uint16 = 256 /* not part of X standard (i.e. X.h) */
+ FamilyWild = 65535
+ FamilyNetname = 254 /* not part of X standard */
+ FamilyKrb5Principal = 253 /* Kerberos 5 principal name */
+ FamilyLocalHost = 252 /* for local non-net authentication */
+)
+
+type Xauth struct {
+ Family uint16
+ Address []byte
+ Number []byte
+ Name string
+ Data []byte
+}
+
+func fileName() string {
+ const slashDotXauthority = "/.Xauthority"
+
+ name := os.Getenv("XAUTHORITY")
+ if name != "" {
+ return name
+ }
+
+ name = os.Getenv("HOME")
+ if name == "" {
+ dir := os.Getenv("USERNAME")
+ if dir == "" {
+ return ""
+ }
+ name = "/users/" + dir
+ }
+
+ if len(name) < 2 {
+ return name + slashDotXauthority[1:]
+ }
+ return name + slashDotXauthority
+}
+
+func GetAuthByAddr(family uint16, address []byte, number []byte, name string) *Xauth {
+ auth_name := fileName()
+ if auth_name == "" {
+ return nil
+ }
+
+ auth_file, err := os.Open(auth_name)
+ if err != nil {
+ return nil
+ }
+ defer auth_file.Close()
+
+ var entry *Xauth
+ for {
+ entry = readAuth(auth_file)
+ if entry == nil {
+ break
+ }
+ /*
+ * Match when:
+ * either family or entry->family are FamilyWild or
+ * family and entry->family are the same and
+ * address and entry->address are the same
+ * and
+ * either number or entry->number are empty or
+ * number and entry->number are the same
+ * and
+ * either name or entry->name are empty or
+ * name and entry->name are the same
+ */
+
+ if (family == FamilyWild || entry.Family == FamilyWild ||
+ (entry.Family == family &&
+ bytes.Equal(address, entry.Address))) &&
+ (len(number) == 0 || len(entry.Number) == 0 ||
+ bytes.Equal(number, entry.Number)) &&
+ (len(name) == 0 || len(entry.Name) == 0 ||
+ entry.Name == name) {
+ break
+ }
+ }
+ return entry
+}
+
+func GetBestAuthByAddr(family uint16, address []byte, number []byte, types []string) *Xauth {
+ auth_name := fileName()
+ if auth_name == "" {
+ return nil
+ }
+
+ auth_file, err := os.Open(auth_name)
+ if err != nil {
+ return nil
+ }
+ defer auth_file.Close()
+
+ var best *Xauth
+ best_type := len(types)
+ for {
+ entry := readAuth(auth_file)
+ if entry == nil {
+ break
+ }
+ /*
+ * Match when:
+ * either family or entry->family are FamilyWild or
+ * family and entry->family are the same and
+ * address and entry->address are the same
+ * and
+ * either number or entry->number are empty or
+ * number and entry->number are the same
+ * and
+ * either name or entry->name are empty or
+ * name and entry->name are the same
+ */
+
+ if (family == FamilyWild || entry.Family == FamilyWild ||
+ (entry.Family == family && bytes.Equal(entry.Address, address))) &&
+ (len(number) == 0 || len(entry.Number) == 0 ||
+ bytes.Equal(number, entry.Number)) {
+ if best_type == 0 {
+ best = entry
+ break
+ }
+ for i := 0; i < best_type; i++ {
+ if types[i] == entry.Name {
+ best = entry
+ best_type = i
+ break
+ }
+ if best_type == 0 {
+ break
+ }
+ continue
+ }
+ }
+ }
+ return best
+}
+
+func readShort(file *os.File) (uint16, error) {
+ var buf [2]byte
+ _, err := io.ReadFull(file, buf[:])
+
+ if err != nil {
+ return 0, err
+ }
+ return uint16(buf[0])*256 + uint16(buf[1]), nil
+}
+
+func readCountedString(file *os.File) ([]byte, error) {
+ len, err := readShort(file)
+ if err != nil {
+ return nil, err
+ }
+
+ buf := make([]byte, len)
+ _, err = io.ReadFull(file, buf)
+ if err != nil {
+ return nil, err
+ }
+
+ return buf, nil
+}
+
+func readAuth(auth_file *os.File) *Xauth {
+ var local Xauth
+
+ var err error
+ local.Family, err = readShort(auth_file)
+ if err != nil {
+ return nil
+ }
+ local.Address, err = readCountedString(auth_file)
+ if err != nil {
+ return nil
+ }
+ local.Number, err = readCountedString(auth_file)
+ if err != nil {
+ return nil
+ }
+ name, err := readCountedString(auth_file)
+ if err != nil {
+ return nil
+ }
+ local.Name = string(name)
+ local.Data, err = readCountedString(auth_file)
+ if err != nil {
+ return nil
+ }
+
+ return &local
+}