-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Fallback to root when user's home directory is not accessible #47524
base: master
Are you sure you want to change the base?
Changes from 2 commits
ed24597
f23e7c3
a3e2b84
66351ed
865d79f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -866,16 +866,24 @@ func getConnFile(conn net.Conn) (*os.File, error) { | |
} | ||
} | ||
|
||
// runCheckHomeDir check's if the active user's $HOME dir exists. | ||
// runCheckHomeDir check's if the active user's $HOME dir exists and is accessible. | ||
func runCheckHomeDir() (errw io.Writer, code int, err error) { | ||
home, err := os.UserHomeDir() | ||
currentUser, err := user.Current() | ||
if err != nil { | ||
return io.Discard, teleport.HomeDirNotFound, nil | ||
return io.Discard, teleport.HomeDirNotAccessible, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks incorrect per this comment:
If there is no user then there is no home dir, yet we are returning the code as if that dir existed (but we couldn't access it). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I agree this is a confusing response. I think a generic |
||
} | ||
if !utils.IsDir(home) { | ||
return io.Discard, teleport.HomeDirNotFound, nil | ||
|
||
err = HasAccessibleHomeDir(currentUser) | ||
switch { | ||
case trace.IsNotFound(err): | ||
code = teleport.HomeDirNotFound | ||
case trace.IsAccessDenied(err): | ||
code = teleport.HomeDirNotAccessible | ||
case err != nil: | ||
code = teleport.HomeDirNotFound | ||
} | ||
return io.Discard, teleport.RemoteCommandSuccess, nil | ||
|
||
return io.Discard, code, nil | ||
} | ||
|
||
// runPark does nothing, forever. | ||
|
@@ -1194,10 +1202,42 @@ func copyCommand(ctx *ServerContext, cmdmsg *ExecCommand) { | |
} | ||
} | ||
|
||
// CheckHomeDir checks if the user's home dir exists | ||
// HasAccessibleHomeDir checks if the given User has access to an existing home directory. | ||
func HasAccessibleHomeDir(localUser *user.User) error { | ||
fi, err := os.Stat(localUser.HomeDir) | ||
if err != nil { | ||
return trace.Wrap(err) | ||
} | ||
|
||
if !fi.IsDir() { | ||
return trace.NotFound("user home is not a directory") | ||
} | ||
|
||
stat, ok := fi.Sys().(*syscall.Stat_t) | ||
if !ok { | ||
return trace.AccessDenied("could not retrieve owner of home directory") | ||
} | ||
|
||
uid := strconv.Itoa(int(stat.Uid)) | ||
gid := strconv.Itoa(int(stat.Gid)) | ||
|
||
if uid == localUser.Uid && gid == localUser.Gid { | ||
return nil | ||
} | ||
|
||
return trace.AccessDenied("user does not own configured home directory") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks incorrect, here are some scenarios:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are great points. We're probably better off not inspecting the the ownership information manually and instead just trying to stat the directory as the target user. This was mostly to avoid having to reexec if we didn't have to, but I think we do have to 😄 I'll get a new commit up for this 👍 |
||
} | ||
|
||
// CheckHomeDir checks if the user's home dir exists and is accessible. This also handles cases where | ||
// the home directory isn't visible to the root user, which HasAccessibleHomeDir doesn't account for. | ||
func CheckHomeDir(localUser *user.User) (bool, error) { | ||
if fi, err := os.Stat(localUser.HomeDir); err == nil { | ||
return fi.IsDir(), nil | ||
err := HasAccessibleHomeDir(localUser) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Funnily enough, simple What is the problem with the root user? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Can you add to this? I'm not sure I understand what you're asking 🤔 |
||
if err == nil { | ||
return true, nil | ||
} | ||
|
||
if trace.IsAccessDenied(err) { | ||
return false, nil | ||
} | ||
|
||
// In some environments, the user's home directory exists but isn't visible to | ||
|
@@ -1229,12 +1269,10 @@ func CheckHomeDir(localUser *user.User) (bool, error) { | |
reexecCommandOSTweaks(cmd) | ||
|
||
if err := cmd.Run(); err != nil { | ||
if cmd.ProcessState.ExitCode() == teleport.HomeDirNotFound { | ||
return false, nil | ||
} | ||
return false, trace.Wrap(err) | ||
} | ||
return true, nil | ||
|
||
return cmd.ProcessState.ExitCode() == teleport.RemoteCommandSuccess, nil | ||
} | ||
|
||
// Spawns a process with the given credentials, outliving the context. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.