func StartCommandExecutor()

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
}