5

Okay, first of all, I know this question has been asked a few times here, but the answers given did not entirely satisfy me. The situation is the following: I have written many scripts to automate various maintenance tasks, with the aim to be fully automatic and requiring not interaction at all once started. Now often root privileges are needed for various tasks (like mounting stuff etc.) but much more often I do not like commands or entire blocks to be executed with superuser rights (like wget, or extracting an archive fetched from the web etc.), to limit damage in the worst case. So obviously to satisfy my aims the script has to be called using sudo or su and drops privileges and regains them, depending on the commands.

Now I have considered a few options but they did not satisfy me entirely and therefore I would like to consult with experts here, to know which would be the best solution (with the aim that the code is easily understandable and logically structured for others as well once published):

1.) Factor out the bits to execute as non root user into an external file and execute that file from the main script using su <user> -c /path/to/file. That methoed however has a couple of disadvantages: First of all it ruins the logical structure of the script and makes things harder to understand and to read, as well as creating problems with defining and using variables.

2.) Define an alias or a function to shorten su <user> -c "command". This is a really bad idea as 80% of the scripts would have that privilege prefix. Apart from that, multi-line commands are problematic (like if structures that contain commands that I do not want to run as root).

3.) Something like su <user> << EOF << ... EOF which would properly handle entire blocks of code. This would be the most elegant solution (because the logical structure of the script is not destroyed) if there was not one problem that bugs me: Syntax highlighting. All major editors I tried use one color for the entire block inside the here doc. It is not exactly nice to read through a script where 80% have no syntax highlighting.

Is there no really elegant way to handle this issue? Something like su <user> -c ( ...) without quotes would be cool. Or should I maybe switch to another shell? (right now I use bash, I heard zsh has a feature that allows setting EUID variables or something like that?) If there is no elegant solution, which approach would be preferable?

3

With zsh, if running as root and you set

EUID=1000

It will set the euid to 1000. The real uid will still be set to 0, so you can go back to EUID 0. Any program that you run would also be able to regain privileges by doing a setuid() but if the intent is to prevent unintentional damage as opposed to guard against malicious software, then that should be enough.

#! /bin/zsh -
GID=1000 # optional
EUID=1000 # drop *effective* privileges

some-potentially-harmful-command-that-doesnt-need-superuser

and-another

EUID=0 some-command-that-needs-superuser

more-non-privileged-commands

EUID=0 UID=1000 # now drop privileges with no coming back 
# alternatively:
# USERNAME=stephane # sets uid, gid, supplementary groups... based on the user db

Note that you can set EUID/UID... for the duration of a command with

UID=1000 the-command

But not UID or USERNAME if the-command is builtin or a function as zsh would not fork a different process so would not be able to restore the real userid.

You can also set EUID/UID/USERNAME in a subshell with:

(EUID=0 USERNAME=stephane; untrusted-application)

(we set EUID to 0 to be able to switch user afterwards).

2

One solution would be a bit of dynamic programming: Create the various unprivileged code fragments as separate files, and use a preprocessor to create the final file. This way the program can trivially be read either as separate bits or as a whole. Communication between processes would have to be done using files, which is a bit more cumbersome but makes it much less likely to leak privileged information to the unprivileged file (since you have to explicitly "leak" every piece of information).

privileged.sh:

echo "Privileged user: $(whoami)"
su - somebody <<'EOF'
%unprivileged.sh%
EOF

unprivileged.sh:

echo "Unprivileged user: $(whoami)"

preprocessor.sh:

while IFS= read -r line
do
    if [[ $line =~ ^%([^%]*)%$ ]]
    then
        cat "${BASH_REMATCH[1]}"
    else
        printf '%s\n' "$line"
    fi
done < privileged.sh > program.sh

Test run:

$ bash preprocessor.sh 
$ sudo bash program.sh 
Privileged user: root
Unprivileged user: somebody
0

3.) Something like su << EOF << ... EOF which would properly handle entire blocks of code. This would be the most elegant solution (because the logical structure of the script is not destroyed) if there was not one problem that bugs me: Syntax highlighting. All major editors I tried use one color for the entire block inside the here doc. It is not exactly nice to read through a script where 80% have no syntax highlighting.

You should be able to define custom syntax highlighting in vim to make it do what you want, this article article may also be of interest.

  • 2
    This does not really answer the question. You are assuming that the OP is using vim, and you are also assuming that whoever else reads the program (the OP cares about others understanding their code). In any case, when quoting external sources, please copy the relevant parts into your answer. Otherwise, if the link ever dies, your answer becomes useless. – terdon Nov 9 '14 at 15:04
  • He mentions he has tried "all major editors," so it sound like OP is open to using another that will do that right job. Nowhere does he mention about others understanding his code, only that he can understand it although this is ultimately up to how he comments his code since editor choice will depend on whoever is viewing his code. This can also be accomplished by porting plugins in vim, which is a major editor. Fair enough on your last point. – TheOneTrueMorty Nov 9 '14 at 15:07
  • 1
    From the OP: " (with the aim that the code is easily understandable and logically structured for others as well once published)". And yes, you can probably configure any serious editor (even vim :) ) to do this but that is not a portable solution – terdon Nov 9 '14 at 15:12
  • I appreciate your answer, though I know that you can adjust the syntax highlighting, the issue is, by default the situation is not the desired one and adjusting the syntax highlighting is not really a good idea, because often the default behavior makes sense (e.g. when embedding a file directly in the script). – GEO Nov 9 '14 at 15:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.