Rsync over SSH getting no tty present

I'm using the following command in root's crontab on Debian.

rsync -vqrlHEAXogDtzhi --log-file=${LOG} --progress --rsync-path="sudo /usr/bin/rsync" --exclude-from=$CONFIG_DIR/excludes -e "ssh -i /home/backups/.ssh/id_rsa" backups@${HOSTNAME}:/ ${BACKUP_DIR}

And I'm getting the following:

sudo: no tty present and no askpass program specified

I have tried adding -t to the ssh command and I get:

Pseudo-terminal will not be allocated because stdin is not a terminal.

I have tried adding -t -t to the ssh command and I get:

protocol version mismatch -- is your shell clean?

I have added a .hushlogin to the backups user on the remote box and confirmed that I can ssh as backups using a key to the remote box with nothing displayed (login is hushed). I still get these messages.

Note that I can ssh as backups to the remote box using a key successfully.

Note that my sudo does not have the -tt option.

Note that the following is set in source and destination's /etc/sudoers file:

backups ALL= NOPASSWD:/usr/bin/rsync

Note that my /etc/sudoers file does not have any reference to:

Defaults    requiretty

Note that I won't echo my password in the command.

How can I skin this cat? :|

Thanks


Solution 1:

Sometimes you think too hard about things.

Rsync was not installed on the remote system.

/facepalm

Solution 2:

Putting this here so I can remember & share this trick:

rsync -av -e "ssh -tt" --rsync-path="stty raw -echo; sudo /usr/bin/rsync"   user@${HOSTNAME}:/ ${DEST_DIR}

This method seems to bypass the requirement for a tty as enforced on some system's default /etc/sudoers file with Defaults requiretty. This information was crafted after reviewing this SO question & answers.

In that answer, they recommend removing Defaults requiretty from /etc/sudoers. This is the easier method. However, if you are unable to modify the remote host /etc/sudoers to remove this configuration option, you can try forcing the local rsync to use ssh -tt. This option for ssh is described in the ssh client manual page like this:

Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

Thus, we force ssh to allocate a pseudo-tty to avoid the error:

Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Inappropriate ioctl for device
sudo: sorry, you must have a tty to run sudo

Then, the --rsync-path is overridden with a command to do the following:

stty raw -echo; sudo /usr/bin/rsync

stty raw -echo is to set the line discipline of the remote terminal as pass through. This effectively causes it to behave like a pipe that would be used instead of a pseudo-terminal without -tt.

Then the remote rsync command will be sudo /usr/bin/rsync, which now has a pseudo-tty and will pass the requiretty check for sudo.

Solution 3:

  1. You don't need sudo if the cron job is excecuting as root.
  2. There's a whole slew of unnecessary flags: -rlptgoD; remove and replace with -a.
  3. The TTY message from sudo is for the local TTY whereas the -t option to ssh is for the remote TTY. Don't confuse the two.
  4. Don't -v and -q contradict each other?
  5. Your last worry should be whether the local SSH private key is encrypted or not. The former cannot be used with unattended runs (e.g., ones where stdin is not a TTY; they aren't run from a terminal or terminal emulator).

EDIT/UPDATE:

  • I take back 1 and 2.
  • 3 should be about there being no local TTY when cron is running, and SSH doesn't allocate one remotely since there isn't a local one.