// Authentication routines for the HKExSh package herradurakex import ( "bytes" "encoding/csv" "fmt" "io" "io/ioutil" "log" "runtime" "github.com/jameskeane/bcrypt" "golang.org/x/sys/unix" ) func AuthUser(username string, auth string, fname string) (valid bool, allowedCmds string) { b, e := ioutil.ReadFile(fname) if e != nil { valid = false fmt.Println("ERROR: Cannot read hkexsh.passwd file!") log.Fatal(e) } r := csv.NewReader(bytes.NewReader(b)) b = nil runtime.GC() // Paranoia and prob. not effective; kill authFile in b[] r.Comma = ':' r.Comment = '#' r.FieldsPerRecord = 4 // username:salt:authCookie:disallowedCmdList (a,b,...) for { record, err := r.Read() if err == io.EOF { break } if err != nil { log.Fatal(err) } if username == record[0] { tmp, _ := bcrypt.Hash(auth, record[1]) if tmp == record[2] { valid = true } break } //fmt.Println(record) } return } /* ------------- minimal terminal APIs brought in from ssh/terminal * (they have no real business being there as they aren't specific to * ssh, but as of v1.10, early 2018, core go stdlib hasn't yet done * the planned terminal lib reorgs.) * ------------- */ // From github.com/golang/crypto/blob/master/ssh/terminal/util_linux.go const ioctlReadTermios = unix.TCGETS const ioctlWriteTermios = unix.TCSETS // From github.com/golang/crypto/blob/master/ssh/terminal/util.go // State contains the state of a terminal. type State struct { termios unix.Termios } // MakeRaw put the terminal connected to the given file descriptor into raw // mode and returns the previous state of the terminal so that it can be // restored. func MakeRaw(fd int) (*State, error) { termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) if err != nil { return nil, err } oldState := State{termios: *termios} // This attempts to replicate the behaviour documented for cfmakeraw in // the termios(3) manpage. termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON termios.Oflag &^= unix.OPOST termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN termios.Cflag &^= unix.CSIZE | unix.PARENB termios.Cflag |= unix.CS8 termios.Cc[unix.VMIN] = 1 termios.Cc[unix.VTIME] = 0 if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { return nil, err } return &oldState, nil } // GetState returns the current state of a terminal which may be useful to // restore the terminal after a signal. func GetState(fd int) (*State, error) { termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) if err != nil { return nil, err } return &State{termios: *termios}, nil } // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(fd int, state *State) error { return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) } // ReadPassword reads a line of input from a terminal without local echo. This // is commonly used for inputting passwords and other sensitive data. The slice // returned does not include the \n. func ReadPassword(fd int) ([]byte, error) { termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) if err != nil { return nil, err } newState := *termios newState.Lflag &^= unix.ECHO newState.Lflag |= unix.ICANON | unix.ISIG newState.Iflag |= unix.ICRNL if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { return nil, err } defer func() { unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) }() return readPasswordLine(passwordReader(fd)) } // passwordReader is an io.Reader that reads from a specific file descriptor. type passwordReader int func (r passwordReader) Read(buf []byte) (int, error) { return unix.Read(int(r), buf) } // readPasswordLine reads from reader until it finds \n or io.EOF. // The slice returned does not include the \n. // readPasswordLine also ignores any \r it finds. func readPasswordLine(reader io.Reader) ([]byte, error) { var buf [1]byte var ret []byte for { n, err := reader.Read(buf[:]) if n > 0 { switch buf[0] { case '\n': return ret, nil case '\r': // remove \r from passwords on Windows default: ret = append(ret, buf[0]) } continue } if err != nil { if err == io.EOF && len(ret) > 0 { return ret, nil } return ret, err } } }