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.

MountainX
  • 17,948
  • 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 '14 at 08: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 '14 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 '14 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 '14 at 01: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 '14 at 02:11
  • @slm: Thanks. Here are my env vars immediately after running the script. (I can reboot and dump them again.) http://pastebin.com/NT1Zzx0d . My /etc/sudoers is standard Ubuntu 12.04. No changes. I reproduced the problem in a Virtual Box instance that is a clean install of Kubuntu 12.04 as well as on another box. – MountainX Feb 28 '14 at 02:37
  • @slm: I restored the Virtual Box instance to a snapshot immediately before running the script. The env vars are the same as those I posted in last commment for after running the script. – MountainX Feb 28 '14 at 02:41
  • I did my testing on Fedora 19, wonder if there is a diff. b/w the distros? – slm Feb 28 '14 at 02:45
  • @slm - I just created another fresh install of Kubuntu 12.04 on Virtual Box and reproduced the problem again. It happens 100% of the time in this environment. – MountainX Feb 28 '14 at 02:54
  • @slm - here is sudo sudo -V : http://pastebin.com/jDg4768N Let me know what you see that's interesting/different. – MountainX Feb 28 '14 at 03:36
  • @slm - "Password prompt timeout: 0.0 minutes" I think that means the prompt will wait until I enter my password without timing out at all. That setting does not make my system ask for a password every time. The password is cached 15 minutes. – MountainX Feb 28 '14 at 03:58

2 Answers2

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
  • This is an interesting idea, I'm trying to piece together why it works for some of us but not MountainX. – slm Feb 28 '14 at 03: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 '14 at 03: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 '14 at 03: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.

MountainX
  • 17,948
  • 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 08 '19 at 22:10