gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }