diff options
Diffstat (limited to 'xau')
-rw-r--r-- | xau/xau.go | 200 |
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 +} |