3

I have a large bash script (Ubuntu 12.04). The script is designed to be invoked by a regular user; only certain commands within the script run with sudo. It is not an option to run the entire script as root.

Within the script I have a lot of statements similar to these:

echo "blah blah" | sudo tee /path/to/file

and

sudo tee /path/to/file > /dev/null << 'END'
blah blah
END

The form of those statements is largely due to the script being designed to not run as root. I put a lot of work into getting those statements right. (It was a learning experience for me.)

The script works well and I do not want to massively change it. In fact, I don't want to change it at all because it is debugged and working in a production (sort of) environment.

However, I do want to add better logging. So I added the following lines to the beginning of my bash script as per https://stackoverflow.com/a/11886837/463994

#!/bin/bash

>foo.log
exec >  >(tee -a foo.log)
exec 2> >(tee -a foo.log >&2)

However, now when I run the script it asks me for my password for every instance of the sudo/tee command examples shown above (about 50 of them!).

Is there a solution for this that does not require me to significantly change the existing code? I just want to log the output of the script without changing how it runs (including without requiring password entry many times within a short span of time).

Here is code showing the problem:

#!/bin/bash

sudo -k

>foo.log #truncate log file to start fresh
exec >  >(tee -a foo.log)
exec 2> >(tee -a foo.log >&2)

if [ -f fileone.txt ] ; then
    echo "sudo rm fileone.txt"
    sudo rm fileone.txt
fi

echo "sudo touch fileone.txt"
sudo touch fileone.txt

echo "sudo touch filetwo.txt"
sudo touch filetwo.txt

sudo touch /opt/file3.txt
echo "blah blah" | sudo tee /opt/file3.txt
sudo rm /opt/file3.txt

exit

Expected result:

enter password once and whole script runs

Actual result:

have to enter password again for echo "blah blah" | sudo tee /opt/file3.txt and any similar statements of the form given at the top of this question. But only if the logging code at the top of the script is used. Without the logging, there is no problem.

11
  • I tried it and it only asked for my password once. AFAIK, the password timestamp is associated with the tty device, redirecting stdout and stderr shouldn't affect it.
    – Barmar
    Feb 27, 2014 at 8:01
  • 1
    Afraid this is a 'works for me' too. Are you sure you haven't got a configuration issue or have -k or -K with sudo. Also the second answer on that SO question is better.
    – Graeme
    Feb 27, 2014 at 10:34
  • @slm, Graeme, Barmar: I really appreciate all the feedback! I'm troubleshooting it and I will report back on what I find. It's helpful to know that something else is probably causing the issue.
    – MountainX
    Feb 27, 2014 at 22:12
  • @slm, Graeme, Barmar: I found the exact problem! I had to massively alter my question to explain the problem correctly.
    – MountainX
    Feb 28, 2014 at 1:56
  • @MountainX - your example script works perfectly for me, let's focus on your /etc/sudoers file, perhaps you have some options set that are causing this?
    – slm
    Feb 28, 2014 at 2:11

2 Answers 2

2

You have the tty_tickets option enabled in your sudo configuration. This is the default setting. This option tells sudo that if you authenticate by typing your password on one terminal, then this only validates the use of sudo on that terminal.

When you added these redirections, sudo lost the connection with your terminal. (I think sudo uses pam's PAM_TTY setting to determine what terminal it's running on; I don't know how that is determined.) When in doubt, sudo asks all the time.

The tty_tickets option is only useful if you might have left an unattended login session on a terminal somewhere, where a casual passer-by might then try to run sudo to escalate from your account to root. It has no impact against even mildly sophisticated attackers who can plant malware on your account and hijack the next time you run sudo. So there is no real benefit to this option, it's only a hindrance.

To turn off the option, run visudo to edit the sudo configuration and add the line

Defaults !tty_tickets
3
  • This is an interesting idea, I'm trying to piece together why it works for some of us but not MountainX.
    – slm
    Feb 28, 2014 at 3:19
  • If you do a sudo sudo -V you can get all the options that sudo was built w/ + configured w/. Notice this line: Authentication methods: 'pam'. My sudo was also compiled w/ these options: --with-pam --with-pam-login.
    – slm
    Feb 28, 2014 at 3:22
  • Thank you Giles. Since my bash script is an installer, I will need to do this on each machine before the install script is run. Is there an easy way to incorporate this sudo configuration change into the beginning of my script? (I dont' really want the end user to have to run visudo just to do my install.)
    – MountainX
    Feb 28, 2014 at 3:41
0

Building on Giles's answer I came up with this implemention of his suggestion:

First, create this script file:

#!/bin/bash
echo "Defaults !tty_tickets" >> $1
exit 0

Second, include this in the main script, near the beginning:

sudo grep -i "Defaults !tty_tickets" /etc/sudoers 
if [ $? -ne 0 ] ; then
    sudo chmod a+x $SRCDIR/install_scripts/no_tty_tickets.sh
    sudo -E EDITOR=$SRCDIR/install_scripts/no_tty_tickets.sh su -c visudo
fi

It does properly edit /etc/sudoers. Here's the result:

#
# This file MUST be edited with the 'visudo' command as root.
#
...

# 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

Defaults !tty_tickets

This works and gives me the complete solution.

1
  • Make sure to also remove it after the installation is done, editing configuration files on a system without informing the user can lead to a bad reputation
    – Ferrybig
    Mar 8, 2019 at 22:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .