filestash/server/plugin/plg_backend_nfs/auth_helper.go

122 lines
2.8 KiB
Go

package plg_backend_nfs
import (
"bufio"
"os"
"strconv"
"strings"
. "github.com/mickael-kerjean/filestash/server/common"
)
var (
cacheForEtc AppCache
cacheForGroup AppCache
)
const (
DEFAULT_UID = 1000
DEFAULT_GID = 1000
)
func init() {
cacheForEtc = NewAppCache(120, 60)
cacheForGroup = NewAppCache(120, 60)
}
func extractUserInfo(uidHint string, gidHint string, gidsHint string) (uint32, uint32, []uint32) {
// case 1: everything is being sent as "uid=number, gid=number and gids=number,number,number"
if _uid, err := strconv.Atoi(uidHint); err == nil {
var (
uid uint32 = uint32(_uid)
gid uint32
gids []uint32
)
if _gid, err := strconv.Atoi(gidHint); err == nil {
gid = uint32(_gid)
} else {
gid = uid
}
for _, t := range strings.Split(gidsHint, ",") {
if gid, err := strconv.Atoi(strings.TrimSpace(t)); err == nil {
gids = append(gids, uint32(gid))
}
}
return uid, gid, gids
}
// case 2: auto detect everything, aka "uid=www-data gid=www-data gids=..." based on uid=www-data
if _uid, _gid, err := extractFromEtcPasswd(uidHint); err == nil {
return _uid, _gid, extractFromEtcGroup(uidHint, _gid)
}
// case 3: base case
return DEFAULT_UID, DEFAULT_GID, []uint32{}
}
func extractFromEtcPasswd(username string) (uint32, uint32, error) {
if v := cacheForEtc.Get(map[string]string{"username": username}); v != nil {
inCache := v.([]int)
return uint32(inCache[0]), uint32(inCache[1]), nil
}
f, err := os.OpenFile("/etc/passwd", os.O_RDONLY, os.ModePerm)
if err != nil {
return DEFAULT_UID, DEFAULT_GID, err
}
defer f.Close()
lines := bufio.NewReader(f)
for {
line, _, err := lines.ReadLine()
if err != nil {
break
}
s := strings.Split(string(line), ":")
if len(s) != 7 {
continue
} else if username != s[0] {
continue
}
u, err := strconv.Atoi(s[2])
if err != nil {
continue
}
g, err := strconv.Atoi(s[3])
if err != nil {
continue
}
cacheForEtc.Set(map[string]string{"username": username}, []int{u, g})
return uint32(u), uint32(g), nil
}
return DEFAULT_UID, DEFAULT_GID, ErrNotFound
}
func extractFromEtcGroup(username string, primary uint32) []uint32 {
if v := cacheForGroup.Get(map[string]string{"username": username}); v != nil {
return v.([]uint32)
}
f, err := os.OpenFile("/etc/group", os.O_RDONLY, os.ModePerm)
if err != nil {
return []uint32{}
}
defer f.Close()
gids := []uint32{}
lines := bufio.NewReader(f)
for {
line, _, err := lines.ReadLine()
if err != nil {
break
}
s := strings.Split(string(line), ":")
if len(s) != 4 {
continue
} else if username != s[3] {
continue
}
if gid, err := strconv.Atoi(s[2]); err == nil {
ugid := uint32(gid)
if ugid != primary {
gids = append(gids, ugid)
}
}
cacheForGroup.Set(map[string]string{"username": username}, gids)
}
return gids
}