in agent/session/shell/shell_unix.go [64:209]
func StartCommandExecutor(
log log.T,
shellProps mgsContracts.ShellProperties,
isSessionLogger bool,
config agentContracts.Configuration,
plugin *ShellPlugin) (err error) {
log.Info("Starting command executor")
//Start the command with a pty
var cmd *exec.Cmd
appConfig := plugin.context.AppConfig()
if strings.TrimSpace(constants.GetShellCommand(shellProps)) == "" || isSessionLogger {
cmd = exec.Command("sh")
} else {
if appConfig.Agent.ContainerMode || appconfig.PluginNameNonInteractiveCommands == plugin.name {
commands, err := shlex.Split(constants.GetShellCommand(shellProps))
if err != nil {
log.Errorf("Failed to parse commands input: %s\n", err)
return fmt.Errorf("Failed to parse commands input: %s\n", err)
}
if len(commands) > 1 {
cmd = exec.Command(commands[0], commands[1:]...)
} else {
cmd = exec.Command(commands[0])
}
} else {
commandArgs := append(utility.ShellPluginCommandArgs, constants.GetShellCommand(shellProps))
cmd = exec.Command("sh", commandArgs...)
}
}
//TERM is set as linux by pty which has an issue where vi editor screen does not get cleared.
//Setting TERM as xterm-256color as used by standard terminals to fix this issue
cmd.Env = append(os.Environ(), termEnvVariable)
//If LANG environment variable is not set, shell defaults to POSIX which can contain 256 single-byte characters.
//Setting C.UTF-8 as default LANG environment variable as Session Manager supports UTF-8 encoding only.
langEnvVariableValue := os.Getenv(langEnvVariableKey)
if langEnvVariableValue == "" {
cmd.Env = append(cmd.Env, langEnvVariable)
}
var sessionUser string
if !constants.GetRunAsElevated(shellProps) && !isSessionLogger && !appConfig.Agent.ContainerMode {
// We get here only when its a customer shell that needs to be started in a specific user mode.
u := &utility.SessionUtil{}
if config.RunAsEnabled {
if strings.TrimSpace(config.RunAsUser) == "" {
return errors.New("please set the RunAs default user")
}
if os.Geteuid() != 0 {
return errors.New("the agent must run as root to use RunAs")
}
// Check if user exists
if userExists, _ := u.DoesUserExist(config.RunAsUser); !userExists {
// if user does not exist, fail the session
return fmt.Errorf("failed to start pty since RunAs user %s does not exist", config.RunAsUser)
}
sessionUser = config.RunAsUser
} else {
if os.Geteuid() == 0 {
// Start as ssm-user
// Create ssm-user before starting a session.
u.CreateLocalAdminUser(log)
sessionUser = appconfig.DefaultRunAsUserName
} else {
user, _ := user.Current()
sessionUser = user.Username
}
}
// Get the uid and gid of the runas user.
uid, gid, groups, err := getUserCredentials(log, sessionUser)
if err != nil {
return err
}
if os.Geteuid() == 0 {
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid, Groups: groups, NoSetGroups: false}
}
// Setting home environment variable for RunAs user
runAsUserHomeEnvVariable := constants.HomeEnvVariable + sessionUser
cmd.Env = append(cmd.Env, runAsUserHomeEnvVariable)
}
if constants.GetRunAsElevated(shellProps) {
cmd.Env = append(cmd.Env, constants.RootHomeEnvVariable)
}
if appconfig.PluginNameNonInteractiveCommands == plugin.name {
if plugin.separateOutput {
//Open pipeline for reading only
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("Failed to create command output pipe, error: %s\n", err)
}
errorPipe, err := cmd.StderrPipe()
if err != nil {
return fmt.Errorf("Failed to create command err pipe, error: %s\n", err)
}
plugin.stdin = nil
plugin.stdout = nil
plugin.stderrPipe = errorPipe
plugin.stdoutPipe = stdoutPipe
} else {
outputPath := filepath.Join(config.OrchestrationDirectory, mgsConfig.ExecOutputFileName)
outputWriter, err := os.OpenFile(outputPath, appconfig.FileFlagsCreateOrAppendReadWrite, appconfig.ReadWriteAccess)
if err != nil {
return fmt.Errorf("Failed to open file for writing command output. error: %s\n", err)
}
outputReader, err := os.Open(outputPath)
if err != nil {
return fmt.Errorf("Failed to read command output from file %s. error: %s\n", outputPath, err)
}
cmd.Stdout = outputWriter
cmd.Stderr = outputWriter
plugin.stdin = nil
plugin.stdout = outputReader
}
} else {
ptyFile, err = pty.Start(cmd)
if err != nil {
log.Errorf("Failed to start pty: %s\n", err)
return fmt.Errorf("Failed to start pty: %s\n", err)
}
plugin.stdin = ptyFile
plugin.stdout = ptyFile
}
plugin.runAsUser = sessionUser
plugin.execCmd = execcmd.NewExecCmd(cmd)
return nil
}