Fix lint and sonar

This commit is contained in:
Viktor Liu
2025-07-03 09:58:25 +02:00
parent 3e490d974c
commit 9e51d2e8fb
2 changed files with 45 additions and 63 deletions

View File

@@ -73,22 +73,6 @@ func (s *Server) createPtyLoginCommand(localUser *user.User, ptyReq ssh.Pty, ses
return execCmd, nil
}
// createPrivilegedPtySuCommand creates a Pty command using su -l -c for command execution
func (s *Server) createPrivilegedPtySuCommand(localUser *user.User, ptyReq ssh.Pty, session ssh.Session, command string) (*exec.Cmd, error) {
suPath, err := exec.LookPath("su")
if err != nil {
return nil, fmt.Errorf("su command not available: %w", err)
}
// Use su -l -c to execute the command as the target user with login environment
args := []string{"-l", localUser.Username, "-c", command}
execCmd := exec.CommandContext(session.Context(), suPath, args...)
execCmd.Dir = localUser.HomeDir
execCmd.Env = s.preparePtyEnv(localUser, ptyReq, session)
return execCmd, nil
}
// getLoginCmd returns the login command and args for privileged Pty user switching
func (s *Server) getLoginCmd(username string, remoteAddr net.Addr) (string, []string, error) {
loginPath, err := exec.LookPath("login")
@@ -194,19 +178,6 @@ func (s *Server) createExecutorCommand(session ssh.Session, localUser *user.User
return privilegeDropper.CreateExecutorCommand(session.Context(), config)
}
// createDirectCommand creates a command that runs without privilege dropping
func (s *Server) createDirectCommand(session ssh.Session, localUser *user.User) (*exec.Cmd, error) {
log.Debugf("creating direct command for user %s (no user switching needed)", localUser.Username)
shell := getUserShell(localUser.Uid)
args := s.getShellCommandArgs(shell, session.RawCommand())
cmd := exec.CommandContext(session.Context(), args[0], args[1:]...)
cmd.Dir = localUser.HomeDir
return cmd, nil
}
// enableUserSwitching is a no-op on Unix systems
func enableUserSwitching() error {
return nil

View File

@@ -21,52 +21,76 @@ func validateUsername(username string) error {
return fmt.Errorf("username cannot be empty")
}
// Handle domain\username format - extract just the username part for validation
usernameToValidate := username
if idx := strings.LastIndex(username, `\`); idx != -1 {
usernameToValidate = username[idx+1:]
usernameToValidate := extractUsernameFromDomain(username)
if err := validateUsernameLength(usernameToValidate); err != nil {
return err
}
// Windows SAM Account Name limits: 20 characters for users, 16 for computers
// We use 20 as the general limit (applies to username part only)
if len(usernameToValidate) > 20 {
if err := validateUsernameCharacters(usernameToValidate); err != nil {
return err
}
if err := validateUsernameFormat(usernameToValidate); err != nil {
return err
}
warnAboutProblematicCharacters(usernameToValidate)
return nil
}
// extractUsernameFromDomain extracts the username part from domain\username format
func extractUsernameFromDomain(username string) string {
if idx := strings.LastIndex(username, `\`); idx != -1 {
return username[idx+1:]
}
return username
}
// validateUsernameLength checks if username length is within Windows limits
func validateUsernameLength(username string) error {
if len(username) > 20 {
return fmt.Errorf("username too long (max 20 characters for Windows)")
}
return nil
}
// Check for Windows SAM Account Name invalid characters
// Prohibited: " / \ [ ] : ; | = , + * ? < >
// Note: backslash is allowed in full username (domain\user) but not in the user part
// validateUsernameCharacters checks for invalid characters in Windows usernames
func validateUsernameCharacters(username string) error {
invalidChars := []rune{'"', '/', '\\', '[', ']', ':', ';', '|', '=', ',', '+', '*', '?', '<', '>'}
for _, char := range usernameToValidate {
for _, char := range username {
for _, invalid := range invalidChars {
if char == invalid {
return fmt.Errorf("username contains invalid character '%c'", char)
}
}
// Check for control characters (ASCII < 32 or == 127)
if char < 32 || char == 127 {
return fmt.Errorf("username contains control characters")
}
}
return nil
}
// Period cannot be the final character
if strings.HasSuffix(usernameToValidate, ".") {
// validateUsernameFormat checks for invalid username formats and patterns
func validateUsernameFormat(username string) error {
if strings.HasSuffix(username, ".") {
return fmt.Errorf("username cannot end with a period")
}
// Check for reserved patterns
if usernameToValidate == "." || usernameToValidate == ".." {
if username == "." || username == ".." {
return fmt.Errorf("username cannot be '.' or '..'")
}
// Warn about @ character (causes login issues) - check in username part only
if strings.Contains(usernameToValidate, "@") {
log.Warnf("username '%s' contains '@' character which may cause login issues", usernameToValidate)
}
return nil
}
// warnAboutProblematicCharacters warns about characters that may cause issues
func warnAboutProblematicCharacters(username string) {
if strings.Contains(username, "@") {
log.Warnf("username '%s' contains '@' character which may cause login issues", username)
}
}
// createExecutorCommand creates a command using Windows executor for privilege dropping
func (s *Server) createExecutorCommand(session ssh.Session, localUser *user.User, hasPty bool) (*exec.Cmd, error) {
log.Debugf("creating Windows executor command for user %s (Pty: %v)", localUser.Username, hasPty)
@@ -79,19 +103,6 @@ func (s *Server) createExecutorCommand(session ssh.Session, localUser *user.User
return s.createUserSwitchCommand(localUser, session, hasPty)
}
// createDirectCommand creates a command that runs without privilege dropping
func (s *Server) createDirectCommand(session ssh.Session, localUser *user.User) (*exec.Cmd, error) {
log.Debugf("creating direct command for user %s (no user switching needed)", localUser.Username)
shell := getUserShell(localUser.Uid)
args := s.getShellCommandArgs(shell, session.RawCommand())
cmd := exec.CommandContext(session.Context(), args[0], args[1:]...)
cmd.Dir = localUser.HomeDir
return cmd, nil
}
// createUserSwitchCommand creates a command with Windows user switching
func (s *Server) createUserSwitchCommand(localUser *user.User, session ssh.Session, interactive bool) (*exec.Cmd, error) {
username, domain := s.parseUsername(localUser.Username)