client: defer nobody user lookup so Windows doesn't panic (#14790)

In #14742 we introduced a cached lookup of the `nobody` user, which is only ever
called on Unixish machines. But the initial caching was being done in an `init`
block, which meant it was being run on Windows as well. This prevents the Nomad
agent from starting on Windows.

An alternative fix here would be to have a separate `init` block for Windows and
Unix, but this potentially masks incorrect behavior if we accidentally added a
call to the `Nobody()` method on Windows later. This way we're forced to handle
the error in the caller.
This commit is contained in:
Tim Gross
2022-10-04 11:52:12 -04:00
committed by GitHub
parent b147ee214e
commit d3a55915f5
2 changed files with 17 additions and 18 deletions

View File

@@ -40,14 +40,17 @@ func dropDirPermissions(path string, desired os.FileMode) error {
return nil
}
nobody := users.Nobody()
uid, err := getUid(&nobody)
nobody, err := users.Nobody()
if err != nil {
return err
}
gid, err := getGid(&nobody)
uid, err := getUid(nobody)
if err != nil {
return err
}
gid, err := getGid(nobody)
if err != nil {
return err
}

View File

@@ -1,33 +1,29 @@
package users
import (
"fmt"
"os/user"
"sync"
)
// lock is used to serialize all user lookup at the process level, because
// some NSS implementations are not concurrency safe
var lock *sync.Mutex
var lock sync.Mutex
// nobody is a cached copy of the nobody user, which is going to be looked-up
// frequently and is unlikely to be modified on the underlying system.
var nobody user.User
var nobody *user.User
// Nobody returns User data for the "nobody" user on the system, bypassing the
// locking / file read / NSS lookup.
func Nobody() user.User {
// original is immutable via copy by value
return nobody
}
func init() {
lock = new(sync.Mutex)
u, err := Lookup("nobody")
if err != nil {
panic(fmt.Sprintf("unable to lookup the nobody user: %v", err))
func Nobody() (*user.User, error) {
lock.Lock()
defer lock.Unlock()
if nobody != nil {
return nobody, nil
}
nobody = *u
u, err := user.Lookup("nobody")
nobody = u
return u, err
}
// Lookup username while holding a global process lock.