2

Need to redirect 3 bash code files (possibly more in the future) to SSH, escaping them (within the same SSH session) to execute them on remote host. Perfectly fine to list bash code files manually.

First 2 files: functions1, functions2 contains only Bash functions.

chroot_script.sh contains both Bash functions and code outside of a function (scripts are way to long to post here).

Sample code for the context:

cat "functions1" <(echo) "functions2" <(echo) "chroot_script.sh" | ssh -tt ${ssh_command_target} "bash -s" 

chroot_script.sh uses some functions from both "functions1" and "functions2".

<(echo) is to add new line between bash code files (can be removed if there's a better/another way to add new line between bash code files).

I believe the above SSH line/code doesn't work because Bash code files need to be escaped. bash -s just found on internet (don't currently know if I really need -s).

Tried first redirecting like this:

ssh -tt ${ssh_command_target} <"functions1" <"functions2" <"chroot_script.sh" 

The above seems to only redirect 1 of the files in the list.

Do need ssh -tt because inside chroot_script.sh there's Bash code doing chroot on remote host (not the subject of this question, rather showing it for context):

cat << EOF | sudo chroot ${mount_root_path} Bash code EOF 

Expected result: Redirect 3 bash code files to SSH escaping them (within the same SSH session) with new line between each file.

OpenSSL 3.0.13 (same version on the client and SSH server). I have full control of both machines.

Thank you for reading!

Update: /etc/sudoers content (first comments removed):

Defaults env_reset Defaults mail_badpass Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" # This fixes CVE-2005-4890 and possibly breaks some versions of kdesu # (#1011624, https://bugs.kde.org/show_bug.cgi?id=452532) Defaults use_pty # This preserves proxy settings from user environments of root # equivalent users (group sudo) #Defaults:%sudo env_keep += "http_proxy https_proxy ftp_proxy all_proxy no_proxy" # This allows running arbitrary commands, but so does ALL, and it means # different sudoers have their choice of editor respected. #Defaults:%sudo env_keep += "EDITOR" # Completely harmless preservation of a user preference. #Defaults:%sudo env_keep += "GREP_COLOR" # While you shouldn't normally run git as root, you need to with etckeeper #Defaults:%sudo env_keep += "GIT_AUTHOR_* GIT_COMMITTER_*" # Per-user preferences; root won't have sensible values for them. #Defaults:%sudo env_keep += "EMAIL DEBEMAIL DEBFULLNAME" # "sudo scp" or "sudo rsync" should be able to use your SSH agent. #Defaults:%sudo env_keep += "SSH_AGENT_PID SSH_AUTH_SOCK" # Ditto for GPG agent #Defaults:%sudo env_keep += "GPG_AGENT_INFO" # Host alias specification # User alias specification # Cmnd alias specification # User privilege specification root ALL=(ALL:ALL) ALL # Members of the admin group may gain root privileges %admin ALL=(ALL) ALL # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL # See sudoers(5) for more information on "@include" directives: @includedir /etc/sudoers.d 
ls sudoers.d/ README 
3
  • Suggestion: Take a look at the Ansible software suite as a way to execute actions/commands on remote servers that you access via ssh.CommentedMar 9 at 4:35
  • 2
    Even if you didn't want to use Ansible, using scp or even tar over ssh to transfer those files to the target system and then executing them would be better than this rigmarole
    – muru
    CommentedMar 9 at 5:50
  • FYI, the usual term for bash code files is "bash scripts".
    – Barmar
    CommentedMar 9 at 16:11

1 Answer 1

5

You'd use -s when you want bash to take its code from stdin even when passed arguments as in:

<script bash -s arg1-for-the-script arg2-for-the-script 

As otherwise, in <script bash arg1-for-the-script arg2-for-the-script, bash would try to run the arg1-for-the-script script instead (with script on stdin).

In <script bash -s, the -s is superfluous as bash takes the code from stdin when not given any arguments anyway.


Now, as to whether some escaping should be done, yes, but it's probably not the escaping you had in mind, and it's down to the bogus -tt option you're passing to ssh (more on that at Why is this binary file transferred over "ssh -t" being changed?), and that -tt causes problems on the output side as well.

With -tt, sshd on the remote host creates a pseudo terminal for a remote command that expects to do input/output with an interactive user, and ssh's stdin/stdout/stderr is expected to be input/fed to a terminal device in raw mode.

For instance, if a 0x3 byte (^C) is sent to ssh, that will cause a SIGINT to be sent to the remote command, characters read from the script will be interpreted as if key-pressed by the line editor of the remote pseudo-terminal line discipline, with ^? treated as backspace, ^U as erasing the line, etc.

So there are characters that need to be escaped indeed, but they are normally only control characters, and you wouldn't escape them with \ or quoting but with the lnext character (usually ^V).

Moreover, as bash's input is a tty device file, bash (with or without -s) will enter its interactive mode where for instance it issues prompts for the user, reads ~/.bashrc and replaces the limited tty device driver line editor with its own line editor (readline), which handles even more control sequences (note that switch will happen after the tty driver has already processed most if not all of the input in its own line editor), so unless you disable that interactive mode (like with cat | bash or bash -c 'source /dev/stdin' instead of bash), you'd have to do two escapings, one for the tty driver line editor, one for bash's readline.

But that's not what you want to do here, and eventual control characters in those scripts are the least of your concerns when I/O ends up being to a tty device file.

Here, you want to remove that -tt which does not make sense. If sudo requires a terminal, fix the (broken) sudo configuration that causes that (see Why do I need a tty to run sudo if I can sudo without a password?).

cat functions1 functions2 chroot_script.sh | ssh "$ssh_command_target" bash 

Unless you have bogus script files whose last line is not properly delimited, you should not need to insert an extra newline between those files.

Also remember that in bash, parameter expansions must almost always be quoted. If $ssh_command_target is meant to be one argument for ssh, it should be "$ssh_command_target" and if it's an array of arguments (defined for instance as ssh_command_target=( -p 222 "root@$host" )) "${ssh_command_target[@]}".

If you can't fix sudo's configuration, use another method to create a pseudo terminal for it such as the ones using expect or script described at my answer to Why do I need a tty to run sudo if I can sudo without a password?.

Example:

$ echo $'ps -o tty -p "$$"; echo \3 | hexdump -C' | ssh localhost 'SHELL=/bin/sh script -qec " bash <&3 >&4 2>&5 3<&- 4>&- 5>&- " /dev/null 3<&0 </dev/null 4>&1 5>&2' TT pts/3 00000000 03 0a |..| 00000002 

The ps output shows that the bash process has a controlling tty, so a sudo configured with Defaults requiretty would be happy, and the 0x3 byte has been passed undisturbed to bash. In your case, you'd run:

cat functions1 functions2 chroot_script.sh | ssh "$ssh_command_target" 'SHELL=/bin/sh script -qec " exec bash <&3 >&4 2>&5 3<&- 4>&- 5>&- " /dev/null 3<&0 </dev/null 4>&1 5>&2' 

(but again with all that trouble only needed to work around that counterproductive sudo settings).

9
  • Wow! Thank you! I'm trying w/o "-tt" (same SSH code as you advised) and getting this error: bash: cannot set terminal process group (1083960): Inappropriate ioctl for device bash: no job control in this shell on I believe these lines inside chroot_script.sh: cat << EOF | sudo chroot ${MOUNT_ROOT_PATH} typeset -f umount_all ; Would you like to add smth or I should just keep rereading your answer for Nth time:)?
    – strider
    CommentedMar 9 at 21:17
  • The error above was the only reason I added "-tt".
    – strider
    CommentedMar 9 at 21:24
  • Added /etc/sudoers file to the 1st post. Is the line Defaults use_pty the one I need to comment out? Its different from Defaults requiretty in the sudo related post you linked.
    – strider
    CommentedMar 9 at 21:48
  • There's a number of sudo mkdir, sudo umount, sudo mount and other sudo commands (which seem to run fine) inside chroot_script.sh BEFORE the line cat << EOF | sudo chroot.
    – strider
    CommentedMar 9 at 23:03
  • 1
    No, use_pty should be fine though might contribute to your problem. Your problem seems to be elsewhere in that it's not sudo requiring a tty. That cannot set terminal process group suggests a bash with stdin on a tty (and trying to be interactive as a result), but that tty not being its controlling tty. use_pty should not create a pty when stdin is not a tty (like in your cat | sudo chroot), but you may be running into a bug of an older version of sudo (continued)CommentedMar 10 at 6:34

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.