16

I have a long and long-running bash script where a handful of commands need to be run as root while the majority of commands need to be run as the regular user before sudo, because it would mess up file ownership and such.

I came up with some methods, but each of them have some problems

Method 1: Using sudo inside the file

#!/bin/bash
sudo echo "I must be run by root"
touch needsToBeOwnedByUser1
echo "needs to be run by user"
sleep 1000
sudo echo "I, again, must be run by root"

This would look good, from the way the code is written. sudo is written before the few statements that actually need to be run by root, but if the time between each sudo call is too long sudo again asks for a password. Also, if the first execution of sudo fails, e.g. due to an invalid password, the rest of the script is still executed.

Method 2: using sudo to call the file and then change back to the original user when needed

#!/bin/bash
echo "I must be run by root"
su username -c 'touch needsToBeOwnedByUser1'
su username -c 'echo "needs to be run by user"'
su username -c 'sleep 1000'
echo "I, again, must be run by root"

This also sucks, because I need to add su username -c in front of almost every line. Also finding the original username after sudo is possible, but cumbersome.

Is there a better way?

Edit: I only posted small, nonsensical scripts here to show what I am talking about. In the actual script I have some lines that need sudo (starting and stopping services), some lines where it does not matter if there is sudo and quite a lot of lines that really need to be run without sudo.

Dakkaron
  • 274
  • 1
  • 4
  • 13
  • 4
    This is very rarely needed. In most cases, you just run the script with `sudo` if it needs to have elevated permissions. But there's no point in switching to `su username -c` to run an `echo`. In other words, this sounds like an [XY]. Could you [edit] and explain what your script will actually be doing and why you feel you need to be switching users so often? – terdon Jul 25 '17 at 12:26
  • 1
    @ElderGeek did you paste the wrong link? That doesn't even seem related. This probably is a duplicate of [How do I run 'sudo' command inside a script?](https://askubuntu.com/q/425754/85695) but I hope the OP can explain a bit more. – terdon Jul 25 '17 at 12:27
  • @terdon It would seem so. Cleaning up. – Elder Geek Jul 25 '17 at 12:41
  • This is just an example script. I didn't want to paste a 200+ line script in here. I will edit the answer for more details. – Dakkaron Jul 25 '17 at 12:48
  • Have you considered the validate option, which is described in `man sudo`? `-v, --validate` 'Update the user's cached credentials, authenticating the user if necessary. For the sudoers plugin, this extends the sudo timeout for another 15 minutes by default, but does not run a command. Not all security policies support cached credentials.' (If you run it often enough, the sudo authenticating should not timeout.) – sudodus Jul 25 '17 at 12:51
  • Please give an example of a command that will not work with `sudo`. – sudodus Jul 25 '17 at 12:56
  • The validate option does not work that well either, since I have a long-running command in between `sudo` calls. This long-running part is a business application that might run for weeks. The clean-up after that command then requires `sudo` again. So there is no way to call `sudo -v` in between. I've looked into it already. – Dakkaron Jul 25 '17 at 13:06
  • One example, as given in the first paragraph, is any command, that creates files that should not be owned by root, e.g. commands that generate log files, e.g. `some-command > logs/somelogfile.log` as appears quite often in my script. – Dakkaron Jul 25 '17 at 13:08
  • 1) You can run a separate process for the validate task (it must not be run sequentially in you script - For example it can be started with `&` at the end of the command line); 2) You can run `sudo -H ` which means that such files will be owned by root (not by your normal user ID) and it will not overwrite files for your normal user ID, but be written elsewhere, and it should work without problems (as long as you are aware of where it is and how to find it). – sudodus Jul 25 '17 at 13:16
  • Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/62786/discussion-between-sudodus-and-dakkaron). – sudodus Jul 25 '17 at 13:28
  • Please continue the discussion in the chat room, that is provided automatically :-) – sudodus Jul 25 '17 at 13:29
  • Workaround, simple: `chown ${SUDO_USER:-$USER} "messedupfile"` in the end of the script corrects at least the files back to user ownership (analog chgrp). If you NEED to start the script as sudo it helps to remediate the wrong rights and ownerships. – opinion_no9 Feb 28 '21 at 17:24

3 Answers3

6

Regarding method 2, it's easier to use a function. For example:

#!/bin/bash

func(){
    echo "Username: $USER"
    echo "    EUID: $EUID"
}

export -f func

func
su "$SUDO_USER" -c 'func'

$SUDO_USER is the sudoer's username. You could also use $(logname) in its place.

Running on my machine:

$ sudo bash test.sh
[sudo] password for wja: 
Username: root
    EUID: 0
Username: wja
    EUID: 1000
wjandrea
  • 14,109
  • 4
  • 48
  • 98
  • in my case this does not work:`zsh:1: command not found: func` – PiKey Sep 08 '20 at 22:30
  • @PiKey Well, it's written for Bash, not Zsh. Is the `:1` there referring to the function definition (`func(){`) or the call from `su` (`-c 'func'`)? – wjandrea Sep 08 '20 at 22:37
4

By reading man sudoers, one sees:

 PASSWD and NOPASSWD

   By default, sudo requires that a user authenticate him or herself
   before running a command.  This behavior can be modified via the
   NOPASSWD tag.  Like a Runas_Spec, the NOPASSWD tag sets a default for
   the commands that follow it in the Cmnd_Spec_List.  Conversely, the
   PASSWD tag can be used to reverse things.  For example:

   ray     rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm

   would allow the user ray to run /bin/kill, /bin/ls, and /usr/bin/lprm
   as root on the machine rushmore without authenticating himself. 

Thus, you could allow regular on host machine1 to execute command1 and command2 as root, without password authentication with:

reguser machine1 root = NOPASSWD: /usr/local/command1, /usr/local/command2  

but read each of man -k sudo for details.

waltinator
  • 35,099
  • 19
  • 57
  • 93
-1

Maybe this can help:

chmod 775 yourscript.sh

Then you can use sudo inside of the script (without password prompt) And can not use sudo for other commands inside your script.

  • 1
    I fear that does not work. `chmod 775` only allows you to execute the file and does not change the user which is executing the file or their rights. – Dakkaron Apr 14 '20 at 08:57