blob: 9ad9d11dff34c3ff31979d7ae57617807716f4e8 [file] [log] [blame]
package dbus
import (
"encoding/hex"
"os/user"
"strconv"
)
// AuthExternal returns an Auth that authenticates as the given user with the
// EXTERNAL mechanism.
func AuthExternal(user string) Auth {
return authExternal{user}
}
// AuthExternal implements the EXTERNAL authentication mechanism.
type authExternal struct {
user string
}
func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) {
b := make([]byte, 2*len(a.user))
hex.Encode(b, []byte(a.user))
return []byte("EXTERNAL"), b, AuthOk
}
func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) {
return nil, AuthError
}
// ServerAuthExternal implements the EXTERNAL authentication mechanism on the server side.
// If callback is specified it decides whether authenticating as a particular uid is
// allowed, otherwise we allow root and the same user as the server process.
func ServerAuthExternal(callback func(uid uint32) bool) ServerAuth {
return serverAuthExternal{callback}
}
type serverAuthExternal struct {
allowUserCallback func(uid uint32) bool
}
func (a serverAuthExternal) Name() string {
return "EXTERNAL"
}
func (a serverAuthExternal) Supported(tr transport) bool {
trUnix, isOk := tr.(*unixTransport)
return isOk && trUnix.hasPeerUid
}
func (a serverAuthExternal) HandleAuth(b []byte, tr transport) ([]byte, ServerAuthStatus) {
trUnix, isOk := tr.(*unixTransport)
if !isOk {
return nil, ServerAuthRejected
}
userStr, err := hex.DecodeString(string(b))
if err != nil {
return nil, ServerAuthRejected
}
uid, err := strconv.ParseUint(string(userStr), 10, 32)
if err != nil {
userData, err := user.Lookup(string(userStr))
if err != nil {
return nil, ServerAuthRejected
}
uid, err = strconv.ParseUint(userData.Uid, 10, 32)
if err != nil {
return nil, ServerAuthRejected
}
}
// Verify that the user is who he claims to be
if !trUnix.hasPeerUid || trUnix.peerUid != uint32(uid) {
return nil, ServerAuthRejected
}
if a.allowUserCallback != nil {
if a.allowUserCallback(uint32(uid)) {
return nil, ServerAuthOk
}
} else {
/* Default: Allow same user or root */
if uid == 0 {
return nil, ServerAuthOk
}
u, err := user.Current()
if err == nil {
currentUid, err := strconv.ParseUint(u.Uid, 10, 32)
if err == nil && currentUid == uid {
return nil, ServerAuthOk
}
}
}
return nil, ServerAuthRejected
}
func (a serverAuthExternal) HandleData(b []byte) ([]byte, ServerAuthStatus) {
return nil, ServerAuthRejected
}