github.com/BurntSushi/xgb@v0.0.0-20210121224620-deaf085860bc/auth.go (about)

     1  package xgb
     2  
     3  /*
     4  auth.go contains functions to facilitate the parsing of .Xauthority files.
     5  
     6  It is largely unmodified from the original XGB package that I forked.
     7  */
     8  
     9  import (
    10  	"encoding/binary"
    11  	"errors"
    12  	"io"
    13  	"os"
    14  )
    15  
    16  // readAuthority reads the X authority file for the DISPLAY.
    17  // If hostname == "" or hostname == "localhost",
    18  // then use the system's hostname (as returned by os.Hostname) instead.
    19  func readAuthority(hostname, display string) (
    20  	name string, data []byte, err error) {
    21  
    22  	// b is a scratch buffer to use and should be at least 256 bytes long
    23  	// (i.e. it should be able to hold a hostname).
    24  	b := make([]byte, 256)
    25  
    26  	// As per /usr/include/X11/Xauth.h.
    27  	const familyLocal = 256
    28  	const familyWild = 65535
    29  
    30  	if len(hostname) == 0 || hostname == "localhost" {
    31  		hostname, err = os.Hostname()
    32  		if err != nil {
    33  			return "", nil, err
    34  		}
    35  	}
    36  
    37  	fname := os.Getenv("XAUTHORITY")
    38  	if len(fname) == 0 {
    39  		home := os.Getenv("HOME")
    40  		if len(home) == 0 {
    41  			err = errors.New("Xauthority not found: $XAUTHORITY, $HOME not set")
    42  			return "", nil, err
    43  		}
    44  		fname = home + "/.Xauthority"
    45  	}
    46  
    47  	r, err := os.Open(fname)
    48  	if err != nil {
    49  		return "", nil, err
    50  	}
    51  	defer r.Close()
    52  
    53  	for {
    54  		var family uint16
    55  		if err := binary.Read(r, binary.BigEndian, &family); err != nil {
    56  			return "", nil, err
    57  		}
    58  
    59  		addr, err := getString(r, b)
    60  		if err != nil {
    61  			return "", nil, err
    62  		}
    63  
    64  		disp, err := getString(r, b)
    65  		if err != nil {
    66  			return "", nil, err
    67  		}
    68  
    69  		name0, err := getString(r, b)
    70  		if err != nil {
    71  			return "", nil, err
    72  		}
    73  
    74  		data0, err := getBytes(r, b)
    75  		if err != nil {
    76  			return "", nil, err
    77  		}
    78  
    79  		addrmatch := (family == familyWild) ||
    80  			(family == familyLocal && addr == hostname)
    81  		dispmatch := (disp == "") || (disp == display)
    82  
    83  		if addrmatch && dispmatch {
    84  			return name0, data0, nil
    85  		}
    86  	}
    87  	panic("unreachable")
    88  }
    89  
    90  func getBytes(r io.Reader, b []byte) ([]byte, error) {
    91  	var n uint16
    92  	if err := binary.Read(r, binary.BigEndian, &n); err != nil {
    93  		return nil, err
    94  	} else if n > uint16(len(b)) {
    95  		return nil, errors.New("bytes too long for buffer")
    96  	}
    97  
    98  	if _, err := io.ReadFull(r, b[0:n]); err != nil {
    99  		return nil, err
   100  	}
   101  	return b[0:n], nil
   102  }
   103  
   104  func getString(r io.Reader, b []byte) (string, error) {
   105  	b, err := getBytes(r, b)
   106  	if err != nil {
   107  		return "", err
   108  	}
   109  	return string(b), nil
   110  }