func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) {
	for {
		s, err := authReadLine(in)
		if err != nil {
			return err, false
		}
		switch {
		case state == waitingForData && string(s[0]) == "DATA":
			if len(s) != 2 {
				err = authWriteLine(conn.transport, []byte("ERROR"))
				if err != nil {
					return err, false
				}
				continue
			}
			data, status := m.HandleData(s[1])
			switch status {
			case AuthOk, AuthContinue:
				if len(data) != 0 {
					err = authWriteLine(conn.transport, []byte("DATA"), data)
					if err != nil {
						return err, false
					}
				}
				if status == AuthOk {
					state = waitingForOk
				}
			case AuthError:
				err = authWriteLine(conn.transport, []byte("ERROR"))
				if err != nil {
					return err, false
				}
			}
		case state == waitingForData && string(s[0]) == "REJECTED":
			return nil, false
		case state == waitingForData && string(s[0]) == "ERROR":
			err = authWriteLine(conn.transport, []byte("CANCEL"))
			if err != nil {
				return err, false
			}
			state = waitingForReject
		case state == waitingForData && string(s[0]) == "OK":
			if len(s) != 2 {
				err = authWriteLine(conn.transport, []byte("CANCEL"))
				if err != nil {
					return err, false
				}
				state = waitingForReject
			}
			conn.uuid = string(s[1])
			return nil, true
		case state == waitingForData:
			err = authWriteLine(conn.transport, []byte("ERROR"))
			if err != nil {
				return err, false
			}
		case state == waitingForOk && string(s[0]) == "OK":
			if len(s) != 2 {
				err = authWriteLine(conn.transport, []byte("CANCEL"))
				if err != nil {
					return err, false
				}
				state = waitingForReject
			}
			conn.uuid = string(s[1])
			return nil, true
		case state == waitingForOk && string(s[0]) == "REJECTED":
			return nil, false
		case state == waitingForOk && (string(s[0]) == "DATA" ||
			string(s[0]) == "ERROR"):
			err = authWriteLine(conn.transport, []byte("CANCEL"))
			if err != nil {
				return err, false
			}
			state = waitingForReject
		case state == waitingForOk:
			err = authWriteLine(conn.transport, []byte("ERROR"))
			if err != nil {
				return err, false
			}
		case state == waitingForReject && string(s[0]) == "REJECTED":
			return nil, false
		case state == waitingForReject:
			return errors.New("dbus: authentication protocol error"), false
		default:
			panic("dbus: invalid auth state")
		}
	}
}
tryAuth tries to authenticate with m as the mechanism, using state as the
initial authState and in for reading input. It returns (nil, true) on
success, (nil, false) on a REJECTED and (someErr, false) if some other
error occured.
package dbus
import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"os"
	"strconv"
)
type AuthStatus byte
const (
	AuthOk AuthStatus = iota
	AuthContinue
	AuthError
)
type authState byte
const (
	waitingForData authState = iota
	waitingForOk
	waitingForReject
)
type Auth interface {
	FirstData() (name, resp []byte, status AuthStatus)
	HandleData(data []byte) (resp []byte, status AuthStatus)
}
func (conn *Conn) Auth(methods []Auth) error {
	if methods == nil {
		uid := strconv.Itoa(os.Getuid())
		methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
	}
	in := bufio.NewReader(conn.transport)
	err := conn.transport.SendNullByte()
	if err != nil {
		return err
	}
	err = authWriteLine(conn.transport, []byte("AUTH"))
	if err != nil {
		return err
	}
	s, err := authReadLine(in)
	if err != nil {
		return err
	}
	if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) {
		return errors.New("dbus: authentication protocol error")
	}
	s = s[1:]
	for _, v := range s {
		for _, m := range methods {
			if name, data, status := m.FirstData(); bytes.Equal(v, name) {
				var ok bool
				err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data)
				if err != nil {
					return err
				}
				switch status {
				case AuthOk:
					err, ok = conn.tryAuth(m, waitingForOk, in)
				case AuthContinue:
					err, ok = conn.tryAuth(m, waitingForData, in)
				default:
					panic("dbus: invalid authentication status")
				}
				if err != nil {
					return err
				}
				if ok {
					if conn.transport.SupportsUnixFDs() {
						err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD"))
						if err != nil {
							return err
						}
						line, err := authReadLine(in)
						if err != nil {
							return err
						}
						switch {
						case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")):
							conn.EnableUnixFDs()
							conn.unixFD = true
						case bytes.Equal(line[0], []byte("ERROR")):
						default:
							return errors.New("dbus: authentication protocol error")
						}
					}
					err = authWriteLine(conn.transport, []byte("BEGIN"))
					if err != nil {
						return err
					}
					go conn.inWorker()
					go conn.outWorker()
					return nil
				}
			}
		}
	}
	return errors.New("dbus: authentication failed")
}