Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Root home fallback for keep users #47467

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions integration/hostuser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,26 @@ func TestRootHostUsers(t *testing.T) {
})
})

t.Run("test create permanent user with pre-existing home dir", func(t *testing.T) {
users := srv.NewHostUsers(context.Background(), presence, "host_uuid")
expectedHome := filepath.Join("/home", testuser)
require.NoDirExists(t, expectedHome)

require.NoError(t, os.Mkdir(expectedHome, 0700))
t.Cleanup(func() {
os.RemoveAll(expectedHome)
})
closer, err := users.UpsertUser(testuser, services.HostUsersInfo{Mode: services.HostUserModeKeep})
require.NoError(t, err)
require.Nil(t, closer)
t.Cleanup(func() { cleanupUsersAndGroups([]string{testuser}, []string{types.TeleportKeepGroup}) })

u, err := user.Lookup(testuser)
require.NoError(t, err)
require.Equal(t, string(os.PathSeparator), u.HomeDir)
require.DirExists(t, expectedHome)
})

t.Run("test create sudoers enabled users", func(t *testing.T) {
if _, err := exec.LookPath("visudo"); err != nil {
t.Skip("Visudo not found on path")
Expand Down
62 changes: 38 additions & 24 deletions lib/srv/usermgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ type HostUsersBackend interface {
DeleteUser(name string) error
// CreateHomeDirectory creates the users home directory and copies in /etc/skel
CreateHomeDirectory(userHome string, uid, gid string) error
// SetHomeDirectory sets a given user's home directory.
SetHomeDirectory(username, home string) error
// GetDefaultHomeDirectory returns the default home directory path for the given user
GetDefaultHomeDirectory(user string) (string, error)
}
Expand Down Expand Up @@ -246,14 +248,6 @@ var unmanagedUserErr = errors.New("user not managed by teleport")
var staticConversionErr = errors.New("managed host users can not be converted to or from a static host user")

func (u *HostUserManagement) updateUser(hostUser HostUser, ui services.HostUsersInfo) error {
ctx := u.ctx
log := u.log.With(
"host_username", hostUser.Name,
"mode", ui.Mode,
"uid", hostUser.UID,
"gid", hostUser.GID,
)

if ui.Mode == services.HostUserModeKeep {
_, hasKeepGroup := hostUser.Groups[types.TeleportKeepGroup]
if !hasKeepGroup {
Expand All @@ -262,9 +256,8 @@ func (u *HostUserManagement) updateUser(hostUser HostUser, ui services.HostUsers
return trace.Wrap(err)
}

log.DebugContext(ctx, "Creating home directory", "home_path", home)
err = u.backend.CreateHomeDirectory(home, hostUser.UID, hostUser.GID)
if err != nil && !os.IsExist(err) {
hostUser.Home = home
if err := u.setupHomeDirectory(hostUser); err != nil {
return trace.Wrap(err)
}
}
Expand Down Expand Up @@ -349,19 +342,7 @@ func (u *HostUserManagement) createUser(name string, ui services.HostUsersInfo)
return trace.Wrap(err)
}

if userOpts.Home != "" {
log.InfoContext(u.ctx, "Attempting to create home directory", "home", userOpts.Home, "gid", userOpts.GID)
if err := u.backend.CreateHomeDirectory(userOpts.Home, user.Uid, user.Gid); err != nil {
if !os.IsExist(err) {
return trace.Wrap(err)
}
log.InfoContext(u.ctx, "Home directory already exists", "home", userOpts.Home, "gid", userOpts.GID)
} else {
log.InfoContext(u.ctx, "Created home directory", "home", userOpts.Home, "gid", userOpts.GID)
}
}

return nil
return trace.Wrap(u.setupHomeDirectory(HostUser{Name: user.Username, Home: userOpts.Home, UID: user.Uid, GID: user.Gid}))
})

return trace.Wrap(err)
Expand Down Expand Up @@ -739,3 +720,36 @@ func ResolveGroups(logger *slog.Logger, hostUser *HostUser, ui services.HostUser
log.InfoContext(context.Background(), "Resolved user groups", "before", currentGroups, "after", groupSlice)
return groupSlice, nil
}

// setupHomeDirectory tries to create a home directory for the given HostUser. If the directory cannot be created, the user's home directory
// is reset to the root directory
func (u *HostUserManagement) setupHomeDirectory(hostUser HostUser) error {
log := u.log.With(
"host_username", hostUser.Name,
"uid", hostUser.UID,
"gid", hostUser.GID,
"home", hostUser.Home,
)

if hostUser.Home == "" {
return nil
}

log.InfoContext(u.ctx, "Attempting to create home directory")
if err := u.backend.CreateHomeDirectory(hostUser.Home, hostUser.UID, hostUser.GID); err != nil {
if os.IsExist(err) {
log.InfoContext(u.ctx, "Home directory already exists")
} else {
log.WarnContext(u.ctx, "Could not create home directory", "error", err)
}

if err := u.backend.SetHomeDirectory(hostUser.Name, "/"); err != nil {
log.WarnContext(u.ctx, "Could not unset user home after failing to create directory, host may be inaccessible as this user")
return trace.WrapWithMessage(err, "resetting user home after failing to create directory")
}

return nil
}

return nil
}
10 changes: 10 additions & 0 deletions lib/srv/usermgmt_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,13 @@ func (u *HostUsersProvisioningBackend) CreateHomeDirectory(userHome, uidS, gidS

return nil
}

// SetHomeDirectory sets the home directory path for an existing user.
func (u *HostUsersProvisioningBackend) SetHomeDirectory(username, home string) error {
if home == "" {
home = string(os.PathSeparator)
}

_, err := host.SetUserHome(username, home)
return trace.Wrap(err)
}
6 changes: 5 additions & 1 deletion lib/srv/usermgmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,12 @@ func (tm *testHostUserBackend) CreateHomeDirectory(user, uid, gid string) error
return nil
}

func (tm *testHostUserBackend) SetHomeDirectory(username, home string) error {
return nil
}

func (tm *testHostUserBackend) GetDefaultHomeDirectory(user string) (string, error) {
return "", nil
return fmt.Sprintf("/home/%s", user), nil
}

// RemoveSudoersFile implements HostUsersBackend
Expand Down
13 changes: 13 additions & 0 deletions lib/utils/host/hostusers.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,16 @@ func CheckSudoers(contents []byte) error {
}
return trace.Wrap(err)
}

func SetUserHome(username, home string) (exitCode int, err error) {
usermodBin, err := exec.LookPath("usermod")
if err != nil {
return -1, trace.Wrap(err, "cant find usermod binary")
}

// usermod -G (replace groups) (username)
cmd := exec.Command(usermodBin, "--home", home, username)
output, err := cmd.CombinedOutput()
log.Debugf("%s output: %s", cmd.Path, string(output))
return cmd.ProcessState.ExitCode(), trace.Wrap(err)
}
Loading