func()

in lib/ec2macosinit/systemconfig.go [336:478]


func (c *SystemConfigModule) configureSSHD(ctx *ModuleContext) (configChanges bool, err error) {
	// Look for each thing and fix them if found
	sshdFile, err := os.Open(sshdConfigFile)
	if err != nil {
		log.Fatal(err)
	}
	defer sshdFile.Close()

	// Create scanner for the SSHD file
	scanner := bufio.NewScanner(sshdFile)

	// Create a new temporary file, if changes are detected, it will be moved over the existing file
	tempSSHDFile, err := os.CreateTemp("", "sshd_config_fixed.*")
	if err != nil {
		return false, fmt.Errorf("ec2macosinit: error creating %s", tempSSHDFile.Name())
	}
	defer tempSSHDFile.Close()

	// Keep track of line number simply for confirming warning header
	var lineNumber int
	// Track the last line for adding in warning when needed
	var lastLine string
	// Iterate over every line in the file
	for scanner.Scan() {
		lineNumber++
		currentLine := scanner.Text()
		// If this is the first line in the file, look for the warning header and add if missing
		if lineNumber == 1 && currentLine != ConfigurationManagementWarning {
			_, err = tempSSHDFile.WriteString(ConfigurationManagementWarning + "\n")
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			configChanges = true
			lastLine = ConfigurationManagementWarning
		}

		switch {
		// Check if PasswordAuthentication is enabled, if so put in warning and change the config
		// PasswordAuthentication allows SSHD to respond to user password brute force attacks and can result in lowered
		// security, especially if a simple password is set. In EC2, this is undesired and therefore turned off by default
		case strings.Contains(currentLine, "PasswordAuthentication yes"):
			err = checkAndWriteWarning(lastLine, tempSSHDFile)
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			// Overwrite with desired configuration line
			_, err = tempSSHDFile.WriteString("PasswordAuthentication no\n")
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			// Changes detected so this will enforce updating the file later
			configChanges = true

			// Check if PAM is enabled, if so, put in warning and change the config
			// PAM authentication enables challenge-response authentication which can allow brute force attacks on SSHD
			// In EC2, this is undesired and therefore turned off by default
		case strings.TrimSpace(currentLine) == "UsePAM yes":
			err = checkAndWriteWarning(lastLine, tempSSHDFile)
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			// Overwrite with desired configuration line
			_, err = tempSSHDFile.WriteString("UsePAM no\n")
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			// Changes detected so this will enforce updating the file later
			configChanges = true

			// Check if Challenge-response is enabled, if so put in warning and change the config
			// Challenge-response authentication via SSHD can allow brute force attacks for SSHD. In EC2, this is undesired
			// and therefore turned off by default
		case strings.Contains(currentLine, "ChallengeResponseAuthentication yes"):
			err = checkAndWriteWarning(lastLine, tempSSHDFile)
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			// Overwrite with desired configuration line
			_, err = tempSSHDFile.WriteString("ChallengeResponseAuthentication no\n")
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
			// Changes detected so this will enforce updating the file later
			configChanges = true

		default:
			// Otherwise write the line as is to the temp file without modification
			_, err = tempSSHDFile.WriteString(currentLine + "\n")
			if err != nil {
				return false, fmt.Errorf("ec2macosinit: error writing to %s", tempSSHDFile.Name())
			}
		}
		// Rotate the current line to the last line so that comments can be inserted above rewritten lines
		lastLine = currentLine
	}
	if err := scanner.Err(); err != nil {
		return false, fmt.Errorf("ec2macosinit: error reading %s: %s", sshdConfigFile, err)
	}

	// If there was a change detected, then copy the file and restart sshd
	if configChanges {
		// Get the current status of SSHD, if its not running, then it should not be started
		sshdRunning, err := c.checkSSHDReturn()
		if err != nil {
			ctx.Logger.Errorf("ec2macosinit: unable to get SSHD status: %s", err)
		}

		// Move the temporary file to the SSHDConfigFile
		err = os.Rename(tempSSHDFile.Name(), sshdConfigFile)
		if err != nil {
			return false, fmt.Errorf("ec2macosinit: unable to save updated configuration to %s", sshdConfigFile)
		}
		// Temporary files have different permissions by design, correct the permissions for SSHDConfigFile
		err = os.Chmod(sshdConfigFile, 0644)
		if err != nil {
			return false, fmt.Errorf("ec2macosinit: unable to set correct permssions of %s", sshdConfigFile)
		}
		// If SSHD was detected as running, then a restart must happen, if it was not running, the work is complete
		if sshdRunning {
			// Unload and load SSHD, the launchctl method for re-loading SSHD with new configuration
			_, err = executeCommand([]string{"/bin/zsh", "-c", "launchctl unload /System/Library/LaunchDaemons/ssh.plist"}, "", []string{})
			if err != nil {
				ctx.Logger.Errorf("ec2macosinit: unable to stop SSHD %s", err)
				return false, fmt.Errorf("ec2macosinit: unable to stop SSHD %s", err)
			}
			_, err = executeCommand([]string{"/bin/zsh", "-c", "launchctl load -w /System/Library/LaunchDaemons/ssh.plist"}, "", []string{})
			if err != nil {
				ctx.Logger.Errorf("ec2macosinit: unable to restart SSHD %s", err)
				return false, fmt.Errorf("ec2macosinit: unable to restart SSHD %s", err)
			}
			// Add the message to state that config was modified and SSHD was correctly restarted
			ctx.Logger.Info("Modified SSHD configuration and restarted SSHD for new configuration")
		} else {
			// Since SSHD was not running, only change the configuration but no restarting is desired
			ctx.Logger.Info("Modified SSHD configuration, did not restart SSHD since it was not running")
		}
	} else {
		// There were no changes detected from desired state, simply exit and let the temp file be
		ctx.Logger.Info("Did not modify SSHD configuration")
	}
	// Return the message to caller for logging
	return configChanges, nil
}