forked from godbus/dbus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
auth_sha1.go
102 lines (95 loc) · 2.39 KB
/
auth_sha1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package dbus
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/hex"
"os"
)
// AuthCookieSha1 returns an Auth that authenticates as the given user with the
// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home
// directory of the user.
func AuthCookieSha1(user, home string) Auth {
return authCookieSha1{user, home}
}
type authCookieSha1 struct {
user, home string
}
func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) {
b := make([]byte, 2*len(a.user))
hex.Encode(b, []byte(a.user))
return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue
}
func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
challenge := make([]byte, len(data)/2)
_, err := hex.Decode(challenge, data)
if err != nil {
return nil, AuthError
}
b := bytes.Split(challenge, []byte{' '})
if len(b) != 3 {
return nil, AuthError
}
context := b[0]
id := b[1]
svchallenge := b[2]
cookie := a.getCookie(context, id)
if cookie == nil {
return nil, AuthError
}
clchallenge := a.generateChallenge()
if clchallenge == nil {
return nil, AuthError
}
hash := sha1.New()
hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'}))
hexhash := make([]byte, 2*hash.Size())
hex.Encode(hexhash, hash.Sum(nil))
data = append(clchallenge, ' ')
data = append(data, hexhash...)
resp := make([]byte, 2*len(data))
hex.Encode(resp, data)
return resp, AuthOk
}
// getCookie searches for the cookie identified by id in context and returns
// the cookie content or nil. (Since HandleData can't return a specific error,
// but only whether an error occured, this function also doesn't bother to
// return an error.)
func (a authCookieSha1) getCookie(context, id []byte) []byte {
file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
if err != nil {
return nil
}
defer file.Close()
rd := bufio.NewReader(file)
for {
line, err := rd.ReadBytes('\n')
if err != nil {
return nil
}
line = line[:len(line)-1]
b := bytes.Split(line, []byte{' '})
if len(b) != 3 {
return nil
}
if bytes.Equal(b[0], id) {
return b[2]
}
}
}
// generateChallenge returns a random, hex-encoded challenge, or nil on error
// (see above).
func (a authCookieSha1) generateChallenge() []byte {
b := make([]byte, 16)
n, err := rand.Read(b)
if err != nil {
return nil
}
if n != 16 {
return nil
}
enc := make([]byte, 32)
hex.Encode(enc, b)
return enc
}