diff --git a/server/plugin/plg_backend_nfs/auth_helper.go b/server/plugin/plg_backend_nfs/auth_helper.go index 38259b1a..a8b8abea 100644 --- a/server/plugin/plg_backend_nfs/auth_helper.go +++ b/server/plugin/plg_backend_nfs/auth_helper.go @@ -19,13 +19,13 @@ func init() { cacheForGroup = NewAppCache(120, 60) } -func extractUserInfo(uidHint string, gidHint string, gidsHint string) (uint32, uint32, []uint32) { +func extractUserInfo(uidHint string, gidHint string, gidsHint string) (uint32, uint32, []groupLabel) { // 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 + gids []groupLabel ) if _gid, err := strconv.Atoi(gidHint); err == nil { gid = uint32(_gid) @@ -33,8 +33,9 @@ func extractUserInfo(uidHint string, gidHint string, gidsHint string) (uint32, u gid = uid } for _, t := range strings.Split(gidsHint, ",") { - if gid, err := strconv.Atoi(strings.TrimSpace(t)); err == nil { - gids = append(gids, uint32(gid)) + tmp := strings.TrimSpace(t) + if gid, err := strconv.Atoi(tmp); err == nil { + gids = append(gids, groupLabel{uint32(gid), tmp, 0}) } } return uid, gid, gids @@ -44,7 +45,7 @@ func extractUserInfo(uidHint string, gidHint string, gidsHint string) (uint32, u return _uid, _gid, extractFromEtcGroup(uidHint, _gid) } // case 3: base case - return 0, 0, []uint32{} + return 0, 0, []groupLabel{} } func extractFromEtcPasswd(username string) (uint32, uint32, error) { @@ -83,16 +84,22 @@ func extractFromEtcPasswd(username string) (uint32, uint32, error) { return 0, 0, ErrNotFound } -func extractFromEtcGroup(username string, primary uint32) []uint32 { +type groupLabel struct { + id uint32 + label string + priority int +} + +func extractFromEtcGroup(username string, primary uint32) []groupLabel { if v := cacheForGroup.Get(map[string]string{"username": username}); v != nil { - return v.([]uint32) + return v.([]groupLabel) } f, err := os.OpenFile("/etc/group", os.O_RDONLY, os.ModePerm) if err != nil { - return []uint32{} + return []groupLabel{} } defer f.Close() - gids := []uint32{} + gids := []groupLabel{} lines := bufio.NewReader(f) for { line, _, err := lines.ReadLine() @@ -116,7 +123,7 @@ func extractFromEtcGroup(username string, primary uint32) []uint32 { if gid, err := strconv.Atoi(s[2]); err == nil { ugid := uint32(gid) if ugid != primary { - gids = append(gids, ugid) + gids = append(gids, groupLabel{ugid, s[0], 0}) } } cacheForGroup.Set(map[string]string{"username": username}, gids) diff --git a/server/plugin/plg_backend_nfs/auth_unix.go b/server/plugin/plg_backend_nfs/auth_unix.go index 8bb560f0..2e21b9cf 100644 --- a/server/plugin/plg_backend_nfs/auth_unix.go +++ b/server/plugin/plg_backend_nfs/auth_unix.go @@ -3,6 +3,8 @@ package plg_backend_nfs import ( "bytes" "math/rand" + "sort" + "strings" "time" "github.com/vmware/go-nfs-client/nfs/rpc" @@ -21,17 +23,34 @@ type AuthUnix struct { } // ref: RFC5531 - page25 -func NewAuthUnix(machineName string, uid, gid uint32, gids []uint32) rpc.Auth { +func NewAuthUnix(machineName string, uid, gid uint32, gids []groupLabel, gidsHint string) rpc.Auth { w := new(bytes.Buffer) - if len(gids) > 16 { // limit of NFS in AUTH_UNIX - gids = gids[len(gids)-16 : len(gids)] + if len(gids) > 16 { // https://www.rfc-editor.org/rfc/rfc5531.html#page-25 + // when the limit of AUTH_UNIX is reached, we want to filter out the + // groups that are of less of importance + for i, _ := range gids { + score := 0 + for _, h := range strings.Split(gidsHint, ",") { + if strings.Contains(gids[i].label, strings.TrimSpace(h)) { + score += 1 + } + } + gids[i].priority = score + } + sort.Slice(gids, func(i, j int) bool { + return gids[i].priority > gids[j].priority + }) + gids = gids[0:16] + sort.Slice(gids, func(i, j int) bool { + return gids[i].id < gids[j].id + }) } xdr.Write(w, AuthUnix{ Stamp: rand.New(rand.NewSource(time.Now().UnixNano())).Uint32(), Machinename: machineName, Uid: uid, Gid: gid, - Gids: gids, + Gids: toGids(gids), }) return rpc.Auth{ 1, // = AUTH_SYS in RFC5531 diff --git a/server/plugin/plg_backend_nfs/index.go b/server/plugin/plg_backend_nfs/index.go index b3e3c6c9..97d304b5 100644 --- a/server/plugin/plg_backend_nfs/index.go +++ b/server/plugin/plg_backend_nfs/index.go @@ -44,7 +44,7 @@ func (this NfsShare) Init(params map[string]string, app *App) (IBackend, error) if err != nil { return nil, err } - auth := NewAuthUnix(params["machine_name"], uid, gid, gids) + auth := NewAuthUnix(params["machine_name"], uid, gid, gids, params["gids"]) v, err := mount.Mount( params["target"], auth, @@ -52,7 +52,15 @@ func (this NfsShare) Init(params map[string]string, app *App) (IBackend, error) if err != nil { return nil, err } - return NfsShare{mount, v, auth, app.Context, uid, gid, gids}, nil + return NfsShare{mount, v, auth, app.Context, uid, gid, toGids(gids)}, nil +} + +func toGids(gids []groupLabel) []uint32 { + g := make([]uint32, len(gids)) + for _, gid := range gids { + g = append(g, gid.id) + } + return g } func (this NfsShare) LoginForm() Form {