mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 02:15:43 +03:00
This PR eliminates code specific to looking up and caching the uid/gid/user.User object associated with the nobody user in an init block. This code existed before adding the generic users cache and was meant to optimize the one search path we knew would happen often. Now that we have the cache, seems reasonable to eliminate this init block and use the cache instead like for any other user. Also fixes a constraint on the podman (and other) drivers, where building without CGO became problematic on some OS like Fedora IoT where the nobody user cannot be found with the pure-Go standard library. Fixes github.com/hashicorp/nomad-driver-podman/issues/228
117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
//go:build linux
|
|
|
|
package users
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
|
"github.com/shoenig/test/must"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func TestLookup_Linux(t *testing.T) {
|
|
cases := []struct {
|
|
username string
|
|
|
|
expErr error
|
|
expUser *user.User
|
|
}{
|
|
{username: "nobody", expUser: &user.User{Username: "nobody", Uid: "65534", Gid: "65534", Name: "nobody", HomeDir: "/nonexistent"}}, // ubuntu
|
|
{username: "root", expUser: &user.User{Username: "root", Uid: "0", Gid: "0", Name: "root", HomeDir: "/root"}},
|
|
{username: "doesnotexist", expErr: errors.New("user: unknown user doesnotexist")},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.username, func(t *testing.T) {
|
|
u, err := Lookup(tc.username)
|
|
if tc.expErr != nil {
|
|
must.EqError(t, tc.expErr, err.Error())
|
|
} else {
|
|
must.Eq(t, tc.expUser, u)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWriteFileFor_Linux(t *testing.T) {
|
|
// This is really how you have to retrieve umask. See `man 2 umask`
|
|
umask := unix.Umask(0)
|
|
unix.Umask(umask)
|
|
|
|
path := filepath.Join(t.TempDir(), "secret.txt")
|
|
contents := []byte("TOO MANY SECRETS")
|
|
|
|
must.NoError(t, WriteFileFor(path, contents, "nobody"))
|
|
|
|
stat, err := os.Lstat(path)
|
|
must.NoError(t, err)
|
|
must.True(t, stat.Mode().IsRegular(),
|
|
must.Sprintf("expected %s to be a regular file but found %#o", path, stat.Mode()))
|
|
|
|
linuxStat, ok := stat.Sys().(*syscall.Stat_t)
|
|
must.True(t, ok, must.Sprintf("expected stat.Sys() to be a *syscall.Stat_t but found %T", stat.Sys()))
|
|
|
|
current, err := Current()
|
|
must.NoError(t, err)
|
|
|
|
if current.Username == "root" {
|
|
t.Logf("Running as root: asserting %s is owned by nobody", path)
|
|
nobody, err := Lookup("nobody")
|
|
must.NoError(t, err)
|
|
must.Eq(t, nobody.Uid, fmt.Sprintf("%d", linuxStat.Uid))
|
|
must.Eq(t, 0o600&(^umask), int(stat.Mode()))
|
|
} else {
|
|
t.Logf("Running as non-root: asserting %s is world readable", path)
|
|
must.Eq(t, current.Uid, fmt.Sprintf("%d", linuxStat.Uid))
|
|
must.Eq(t, 0o666&(^umask), int(stat.Mode()))
|
|
}
|
|
}
|
|
|
|
// TestSocketFileFor_Linux asserts that when running as root on Linux socket
|
|
// files are created with least permissions. If running as non-root then we
|
|
// leave the socket file as world writable.
|
|
func TestSocketFileFor_Linux(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "api.sock")
|
|
|
|
logger := testlog.HCLogger(t)
|
|
ln, err := SocketFileFor(logger, path, "nobody")
|
|
must.NoError(t, err)
|
|
must.NotNil(t, ln)
|
|
t.Cleanup(func() {
|
|
_ = ln.Close()
|
|
})
|
|
|
|
stat, err := os.Lstat(path)
|
|
must.NoError(t, err)
|
|
must.False(t, stat.Mode().IsRegular(),
|
|
must.Sprintf("expected %s to be a regular file but found %#o", path, stat.Mode()))
|
|
|
|
linuxStat, ok := stat.Sys().(*syscall.Stat_t)
|
|
must.True(t, ok, must.Sprintf("expected stat.Sys() to be a *syscall.Stat_t but found %T", stat.Sys()))
|
|
|
|
current, err := Current()
|
|
must.NoError(t, err)
|
|
|
|
if current.Username == "root" {
|
|
t.Logf("Running as root: asserting %s is owned by nobody", path)
|
|
nobody, err := Lookup("nobody")
|
|
must.NoError(t, err)
|
|
must.Eq(t, nobody.Uid, fmt.Sprintf("%d", linuxStat.Uid))
|
|
must.Eq(t, 0o600, int(stat.Mode().Perm()))
|
|
} else {
|
|
t.Logf("Running as non-root: asserting %s is world writable", path)
|
|
must.Eq(t, current.Uid, fmt.Sprintf("%d", linuxStat.Uid))
|
|
must.Eq(t, 0o666, int(stat.Mode().Perm()))
|
|
}
|
|
}
|