From badc90c4969884e6229e48f79282f8373f4343f0 Mon Sep 17 00:00:00 2001 From: Erik Tate Date: Thu, 10 Oct 2024 15:27:10 -0400 Subject: [PATCH] falling back to root as home directory for keep users when expected home directory already exists --- integration/hostuser_test.go | 20 ++++++++++++ lib/srv/usermgmt.go | 62 ++++++++++++++++++++++-------------- lib/srv/usermgmt_linux.go | 10 ++++++ lib/srv/usermgmt_test.go | 4 +++ lib/utils/host/hostusers.go | 13 ++++++++ 5 files changed, 85 insertions(+), 24 deletions(-) diff --git a/integration/hostuser_test.go b/integration/hostuser_test.go index 23f385d045c4d..64d773daf8d16 100644 --- a/integration/hostuser_test.go +++ b/integration/hostuser_test.go @@ -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") diff --git a/lib/srv/usermgmt.go b/lib/srv/usermgmt.go index 23397f8ef11d0..99200873eb150 100644 --- a/lib/srv/usermgmt.go +++ b/lib/srv/usermgmt.go @@ -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) } @@ -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 { @@ -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) } } @@ -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) @@ -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 +} diff --git a/lib/srv/usermgmt_linux.go b/lib/srv/usermgmt_linux.go index 3626a599beb72..399f66f511cc0 100644 --- a/lib/srv/usermgmt_linux.go +++ b/lib/srv/usermgmt_linux.go @@ -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) +} diff --git a/lib/srv/usermgmt_test.go b/lib/srv/usermgmt_test.go index fb07adddf6a34..75bcf4e5d0314 100644 --- a/lib/srv/usermgmt_test.go +++ b/lib/srv/usermgmt_test.go @@ -166,6 +166,10 @@ 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 } diff --git a/lib/utils/host/hostusers.go b/lib/utils/host/hostusers.go index 563d5c8de23f2..596a6c07a9d89 100644 --- a/lib/utils/host/hostusers.go +++ b/lib/utils/host/hostusers.go @@ -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) +}