5
5
"bytes"
6
6
"errors"
7
7
"io"
8
+ "os/user"
8
9
)
9
10
10
11
// AuthStatus represents the Status of an authentication mechanism.
@@ -30,26 +31,30 @@ const (
30
31
waitingForReject
31
32
)
32
33
33
- // AuthMechanisms lists all authentication mechanisms that are tried. To
34
- // implement your own mechanism, just add it to this map before connecting. The
35
- // key must be the name that is used for the AUTH command.
36
- var AuthMechanisms = map [string ]AuthMechanism {
37
- "DBUS_COOKIE_SHA1" : AuthCookieSha1 {},
38
- "EXTERNAL" : AuthExternal {},
39
- }
40
-
41
- // AuthMechanism defines the behaviour of an authentication mechanism.
42
- type AuthMechanism interface {
43
- // Return the argument to the first AUTH command and the next status.
44
- FirstData () (resp []byte , status AuthStatus )
34
+ // Auth defines the behaviour of an authentication mechanism.
35
+ type Auth interface {
36
+ // Return the name of the mechnism, the argument to the first AUTH command
37
+ // and the next status.
38
+ FirstData () (name , resp []byte , status AuthStatus )
45
39
46
40
// Process the given DATA command, and return the argument to the DATA
47
41
// command and the next status. If len(resp) == 0, no DATA command is sent.
48
42
HandleData (data []byte ) (resp []byte , status AuthStatus )
49
43
}
50
44
51
- // auth does the whole authentication stuff.
52
- func (conn * Conn ) auth () error {
45
+ // Auth authenticates the connection, trying the given list of authentication
46
+ // mechanisms (in that order). If nil is passed, the EXTERNAL and
47
+ // DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private
48
+ // connections, this method must be called before sending any messages to the
49
+ // bus. Auth must not be called on shared connections.
50
+ func (conn * Conn ) Auth (methods []Auth ) error {
51
+ if methods == nil {
52
+ u , err := user .Current ()
53
+ if err != nil {
54
+ return err
55
+ }
56
+ methods = []Auth {AuthExternal (u .Username ), AuthCookieSha1 (u .Username , u .HomeDir )}
57
+ }
53
58
in := bufio .NewReader (conn .transport )
54
59
_ , err := conn .transport .Write ([]byte {0 })
55
60
if err != nil {
@@ -68,47 +73,52 @@ func (conn *Conn) auth() error {
68
73
}
69
74
s = s [1 :]
70
75
for _ , v := range s {
71
- if m , ok := AuthMechanisms [string (v )]; ok {
72
- data , status := m .FirstData ()
73
- err = authWriteLine (conn .transport , []byte ("AUTH" ), []byte (v ), data )
74
- if err != nil {
75
- return err
76
- }
77
- switch status {
78
- case AuthOk :
79
- err , ok = conn .tryAuth (m , waitingForOk , in )
80
- case AuthContinue :
81
- err , ok = conn .tryAuth (m , waitingForData , in )
82
- default :
83
- panic ("invalid authentication status" )
84
- }
85
- if err != nil {
86
- return err
87
- }
88
- if ok {
89
- if conn .transport .SupportsUnixFDs () {
90
- err = authWriteLine (conn , []byte ("NEGOTIATE_UNIX_FD" ))
91
- if err != nil {
92
- return err
76
+ for _ , m := range methods {
77
+ if name , data , status := m .FirstData (); bytes .Equal (v , name ) {
78
+ var ok bool
79
+ err = authWriteLine (conn .transport , []byte ("AUTH" ), []byte (v ), data )
80
+ if err != nil {
81
+ return err
82
+ }
83
+ switch status {
84
+ case AuthOk :
85
+ err , ok = conn .tryAuth (m , waitingForOk , in )
86
+ case AuthContinue :
87
+ err , ok = conn .tryAuth (m , waitingForData , in )
88
+ default :
89
+ panic ("invalid authentication status" )
90
+ }
91
+ if err != nil {
92
+ return err
93
+ }
94
+ if ok {
95
+ if conn .transport .SupportsUnixFDs () {
96
+ err = authWriteLine (conn , []byte ("NEGOTIATE_UNIX_FD" ))
97
+ if err != nil {
98
+ return err
99
+ }
100
+ line , err := authReadLine (in )
101
+ if err != nil {
102
+ return err
103
+ }
104
+ switch {
105
+ case bytes .Equal (line [0 ], []byte ("AGREE_UNIX_FD" )):
106
+ conn .EnableUnixFDs ()
107
+ conn .unixFD = true
108
+ case bytes .Equal (line [0 ], []byte ("ERROR" )):
109
+ default :
110
+ return errors .New ("authentication protocol error" )
111
+ }
93
112
}
94
- line , err := authReadLine ( in )
113
+ err = authWriteLine ( conn . transport , [] byte ( "BEGIN" ) )
95
114
if err != nil {
96
115
return err
97
116
}
98
- switch {
99
- case bytes .Equal (line [0 ], []byte ("AGREE_UNIX_FD" )):
100
- conn .EnableUnixFDs ()
101
- conn .unixFD = true
102
- case bytes .Equal (line [0 ], []byte ("ERROR" )):
103
- default :
104
- return errors .New ("authentication protocol error" )
105
- }
106
- }
107
- err = authWriteLine (conn .transport , []byte ("BEGIN" ))
108
- if err != nil {
109
- return err
117
+ go conn .inWorker ()
118
+ go conn .outWorker ()
119
+ go conn .serials ()
120
+ return nil
110
121
}
111
- return nil
112
122
}
113
123
}
114
124
}
@@ -119,7 +129,7 @@ func (conn *Conn) auth() error {
119
129
// initial authState and in for reading input. It returns (nil, true) on
120
130
// success, (nil, false) on a REJECTED and (someErr, false) if some other
121
131
// error occured.
122
- func (conn * Conn ) tryAuth (m AuthMechanism , state authState , in * bufio.Reader ) (error , bool ) {
132
+ func (conn * Conn ) tryAuth (m Auth , state authState , in * bufio.Reader ) (error , bool ) {
123
133
for {
124
134
s , err := authReadLine (in )
125
135
if err != nil {
0 commit comments