LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices


Reply
  Search this Thread
Old 01-10-2011, 09:11 AM   #1
kostya
Member
 
Registered: Mar 2010
Location: Moscow, Russia
Distribution: Ubuntu Studio, antix(mepis), Fedora, FreeBSD
Posts: 174
Blog Entries: 5

Rep: Reputation: 18
interactive bash script to ask for superuser password


Hi everyone.
This is an old question asked many times, which, however, is NEVER answered directly in any manual I've checked. So...

I'm writing a bash install script (instead of a rpm or .deb package) that must be run by a normal user.
Then at a certain point the script needs to change to superuser (asking for password and receiving it) and the rest of the script to be executed in the superuser mode in order to install what I mean to install.

I know how `sudo ...` or `su `root -c "..."` or `gnome-terminal -e ...` can achieve this purpose by creating certain batch files and then give them as argument to these commands. That's NOT what I'm asking, however.

I want to know how I can make the script interactively switch to superuser mode and go on running the rest of the script (can be a lot of code) in that mode. I don't mind if it opens a separate terminal window to do that; just how can that be achieved?

Thanks in advance, hope I'm expressing myself clear enough .
 
Old 01-10-2011, 10:35 AM   #2
Snark1994
Senior Member
 
Registered: Sep 2010
Distribution: Debian
Posts: 1,632
Blog Entries: 3

Rep: Reputation: 346Reputation: 346Reputation: 346Reputation: 346
If you include one 'sudo' command in the script, then any other commands prefixed by sudo will run without asking for passwords

Code:
#!/bin/bash
echo `iwconfig` 1> normal
sudo echo "Thanks for the password"
echo `sudo iwconfig` &> su
diff normal su -q
That's a rather clumsy way of showing that the sudo command remembered the password (root's output of iwconfig contains the encryption key of wlan0, and accordingly diff says the files are different)

Last edited by Snark1994; 01-10-2011 at 10:50 AM. Reason: Added code example
 
Old 01-11-2011, 03:10 AM   #3
kostya
Member
 
Registered: Mar 2010
Location: Moscow, Russia
Distribution: Ubuntu Studio, antix(mepis), Fedora, FreeBSD
Posts: 174

Original Poster
Blog Entries: 5

Rep: Reputation: 18
OK, great thanks. I'll try this one out; however, let me describe just WHY I'm thinking of this "abnormal" thing I'm asking about.
I often have to help beginners to install linux, and quite often they're people who're not going to be really deep into it. Say, after finishing installation I just noticed that I forgot to install a iptables script which I usually use. But going back to my friend's place is taking time...

So my dirty fix is: I email him a file, bash script executable, which will install the needed files into the system once the user clicks on it. Such a dirty fix when small changes are needed to have it up and running ASAP.
Then, as the system in question may not have the "/etc/sudoers" file setup properly (unless it is Ubuntu), using `sudo $command` may not work. Therefore, starting a root subshell will be more universal. But in the Advanced Bash Scripting Guide in the chapter on "subshells" there is nothing about starting a different user subshell inside a script.
So I wonder if it is possible, or I'll always have to define a huge piece of code as $COMMAND and then use
Code:
`su root -c "$COMMAND"`
or better still
Code:
`gnome-terminal -e $COMMAND`
move.
At least, in the install scripts I studied folks use this approach.
 
Old 01-12-2011, 04:39 PM   #4
Snark1994
Senior Member
 
Registered: Sep 2010
Distribution: Debian
Posts: 1,632
Blog Entries: 3

Rep: Reputation: 346Reputation: 346Reputation: 346Reputation: 346
I had a play around and looked in the man pages, but everything I tried just took me to a root prompt, then executed the rest of the script once I quit that... Sorry
 
Old 01-13-2011, 12:16 AM   #5
kostya
Member
 
Registered: Mar 2010
Location: Moscow, Russia
Distribution: Ubuntu Studio, antix(mepis), Fedora, FreeBSD
Posts: 174

Original Poster
Blog Entries: 5

Rep: Reputation: 18
Quote:
Originally Posted by Snark1994 View Post
I had a play around and looked in the man pages, but everything I tried just took me to a root prompt, then executed the rest of the script once I quit that... Sorry
Yea, seems to be a tricky thing, right ?
OK, so far I'm using this way:
Code:
#!/bin/bash
cat <<-'EOF' >/tmp/myFile
...............................
....my script text goes here...
...............................
EOF
chmod +x /tmp/myFile
xterm -e su root -c "cp /tmp/myFile /usr/bin"
Avoiding variables like $myfile makes things easier when passing arguments to `su`. XTERM creates a window for the user to type in his password.
But it seems one cannot supply more than ONE command to `su` in a non-interactive way.
...Well ACTUALLY, all the stuff can be done without root privs and then only the crucial operation like copying it into SYSTEM location be done with `su root`.

But hey, I wanna know in general, if it is possible in a bash script to start a non-interactive subshell from another UID. Or should one use other languages for that purpose?
OR, alternatively, how can one supply several commands to `su`? I'll try several things and report my results here, too.

Thanks for your answers anyway.
Kostya

Last edited by kostya; 01-13-2011 at 12:23 AM.
 
Old 01-13-2011, 02:44 AM   #6
kostya
Member
 
Registered: Mar 2010
Location: Moscow, Russia
Distribution: Ubuntu Studio, antix(mepis), Fedora, FreeBSD
Posts: 174

Original Poster
Blog Entries: 5

Rep: Reputation: 18
Quote:
Originally Posted by kostya View Post
...
But it seems one cannot supply more than ONE command to `su` in a non-interactive way.
...how can one supply several commands to `su`?
Ehm, sorry that I didn't read enough documentation before asking these, he-he. In fact, the `su` command seems to be executing just another instance of bash (a subshell), only doing so as superuser. Therefore, a succession of commands can be passed on to `su -c` just as we do in normal bash shell, when we pass on a whole script of commands, each command ending with ";", as in:
Code:
su -c 'cd /root; mkdir mydir; touch mydir/file'
The above simple command succession worked perfectly fine once I tried it. It works the same in:
Code:
xterm -e su -c 'cd /root; mkdir mydir; touch mydir/file'
I'll try later on some more complicated stuff with interactive tricks and report the results.
If it works OK, then this will be the answer to my question.

Bye!

Last edited by kostya; 01-13-2011 at 03:27 AM.
 
Old 01-13-2011, 03:44 AM   #7
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Code:
#!/bin/bash
if [ -z "$BASH_LINENO" ] || [ $BASH_LINENO -gt 0 ]; then
    [ -n "$BASH_ARGV" ] && cmd="$BASH_ARGV" || cmd="$BASH_SOURCE"
    case "$cmd" in
        ""|/*|./*|../*) ;;
        *) cmd="./$cmd" ;;
    esac
    if [ -f "$cmd" ]; then
        chmod a+rx "$cmd" &>/dev/null
        echo -n "root "
        su -c "env TRIEDWITHSU=1 \"${cmd//\"/\\\"}\"" root
        return $?
    fi
    echo "You have a typo there." >&2
    return 1
fi
if [ `id -u` -ne 0 ]; then
    if [ -n "$TRIEDWITHSU" ]; then
        echo "Failed to become root." >&2
        exit 1
    fi
    chmod a+rx "$0" &>/dev/null
    echo -n "root "
    su -c "env TRIEDWITHSU=1 \"${0//\"/\\\"}\"" root
    exit $?
fi
echo "Now running as `id -un`:`id -gn`."
Feel free to omit the last echo; its there just for debugging purposes.

It is more complex than is really needed, but this way the user does not need to set any permission bits.

You can tell the user to save the script as say fixer.txt in their home directory.
Then, they need to open a terminal and type
Code:
. fixer.txt
to run the script.

The scriptlet at the beginning checks whether it's being sourced or executed, and works accordingly. Before su-ing, it adds read and execute bits to itself. It is completely automagic: it uses various bash variables to find out its own name and path.
Nominal Animal

Last edited by Nominal Animal; 03-21-2011 at 03:23 AM.
 
Old 01-13-2011, 07:36 AM   #8
kostya
Member
 
Registered: Mar 2010
Location: Moscow, Russia
Distribution: Ubuntu Studio, antix(mepis), Fedora, FreeBSD
Posts: 174

Original Poster
Blog Entries: 5

Rep: Reputation: 18
Why thank you for this interesting example, must take a closer study later on .
You know, I learn better from examples, than from "dry theory"...
 
Old 01-13-2011, 10:49 PM   #9
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
I'm happy to help.

Here's a breakdown on the scriptlet (from my above post #7):
  • The first if clause is executed if the script was sourced (via source or .).
    Bash provides a variable BASH_LINENO, which is nonzero for sourced scripts.
  • If the script was sourced, it may have been specified with just the file name (in the current directory).
    Since the current directory is probably not in PATH, we may need to prepend the current directory to it, to be able to execute it.
    This is what the case ... esac block does.
  • [ -f file ] is true, if and only if file exists and is a regular file.
  • Variables must be put in double quotes to avoid filename expansion. If, for example, you test [ -f $name ],
    and name has value *, you actually test if there is a single file in the current directory. (If there are more, the shell will error out, because [ -f name1 name2 ] does not work.)
    So always use [ -f "$name" ] instead.
  • The above is not just for tests, it applies everywhere in Bash scripts. Quote your variables, unless you need filename expansion.
  • The file name may contain double quotes and spaces, so we cannot just supply it directly to su in a string,
    because su would just use the first word as the file name and fail.
    Within a doublequoted string \"${cmd//\"/\\\"}\" produces $cmd, but in double quotes, and with all double quotes in (the value of) cmd escaped.
  • `id -u` resolves to the UID number of the current process. It will be zero for superuser.
  • There may be some configuration where su succeeds but does not get elevated rights.
    If we just tried again, we might end up in an endless loop. Without configured limits, this will eventually use all resources, kick in the dreaded OOM killer (which kills some processes trying to free up resources). Nasty. And if the user automatically saves their session at exit, they are screwed: they'll get the half dead session at next login, too.
    Both su calls in this script set environment variable TRIEDWITHSU to 1, so they can detect that they've already tried su and stop, avoiding the possible endless loop.
  • If the script was executed (and not sourced), $0 contains the script name and path.
    Since su takes the command as a string, we need it doublequoted in a doublequoted string, with all double quotes escaped.
    Thus, \"${0//\"/\\\"}\" is used. (The pattern is same as for cmd variable above, of course.)
As I said, this is a bit more complex than is really necessary, but this works even if the user has a localized non-English desktop, and the script name has to be something as complex as Frï'X - Garble garble garble for the user to follow the directions you give.

I think it's still sensitive to backslashes (\), variable expansion ($), and history expansion (!), so avoid those three characters in the file names. They are escapable, but I'm striving for maximally useful, not perfect

If the patterns interest you, you can test them via e.g.
Code:
x="It's a Chëëzbrgr!" ; echo "x becomes \"${x//\"/\\\"}\" in the output"
Nominal Animal

Last edited by Nominal Animal; 03-21-2011 at 03:16 AM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
bash interactive installation script Softsmid Linux - Newbie 9 02-21-2010 07:26 PM
setting a timeout in an interactive bash shell script steven.c.banks Linux - General 2 01-23-2009 04:07 PM
BASH - How to open an interactive script from a non interactive script..... OldGaf Programming 4 06-29-2008 04:34 PM
bash script works when interactive, endless loop when started via cron dguy Linux - General 5 04-10-2006 11:39 AM
bash script that uses username/password paul_mat Linux - Software 2 10-25-2005 10:44 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - General

All times are GMT -5. The time now is 01:45 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration