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