auth_sha1.go 2.4 KB

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