Writing a bash script that performs operations that require root permissions - bash

I'm trying to write a bash script that sets up my web development environment in ubuntu. As part of the process of setting up the script, it needs to edit files that are owned by root. It also needs to create fields in the public_html directory of the user that runs the script.
Should I therefore require that the script be run as the superuser? If it should, then how do I get it to access the current user's username? I would normally use the $USER variable, but I can't do that if the script is being run as the superuser. If I'm not the superuser, how can I get the script to request super user privileges for certain operations, while not requiring the user to type in a password for every operation that requires super user privileges.
Thanks

You can use the -E flag for sudo to preserve the environment variables, or, you can set up sudoers to preserve the environment on a per-command basis.
You can also set up the sudoers file to not ask for a password on a per-command basis, for example, to allow user xy to use smbmount without asking for a password:
xy ALL=NOPASSWD: /usr/bin/smbmount
In your case, it would be enough to just store the current user in a variable before invoking sudo, and use the already saved username:
CURRENT_USER=$USER
sudo yourscript.sh $CURRENT_USER
Then read the username from $1.
You can also use the SUDO_USER env variable, which is set to the user who is invoking sudo.

Insert a check at the top of the script:
# Make sure only root can run this script
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
exit 1
fi
In this way when you run it without the root privileges you will be prompted, then you can simply rerun it the right way with:
sudo yourscript.sh
More infos at http://www.cyberciti.biz/tips/shell-root-user-check-script.html

There's a command named sudo for this purpose. It lets you specify that certain users can run certain commands as root (or another user).

If your users have root access anyway, you could just write a script that must be run as root and takes an username as parameter, instead of picking up the username.
Alternatively, one way of picking up the login username in an interactive shell is:
stat -Lc %U /proc/self/fd/0
This retrieves the ovner of the tty associated with stdin.

Just make it a setuid file. Or use sudo which is probably safer, since you can limit who gets to run it.
chmod 4755 script.sh

In Ubuntu, there's the SUDO_USER environment variable.
So, you can just run your script sudo somescript.sh and have it pull the invoking user's username $SUDO_USER.
Not sure on other dists, though.

Related

Remember root password throughout script using Bash

Background
I have a long bash script which setup a large environment of interconnected software, taking several hours to complete. A few of the tasks it performs need to be run as root, for which I use sudo .... The whole process is then paused until the user notices and types in the root password. I seek some way for the user to type in the root password only at the beginning of the script, and then automatically supply it when required by sudo later.
My thoughts on possible (bad) solutions
I could store the password directly in a variable and then supply it using
echo "${root_password}" | sudo -S ...
but something tells me that this is bad practice.
Another workaround would be to force the user to run the entire script as root, but wouldn't that lead to different permissions for all of the files generated without the use of sudo?
You can prompt it at the start of your script, so it is not plain text hard saved.
Example:
#!/bin/bash
read -s -p "[sudo] sudo password for $(whoami): " pass
echo $pass | sudo -S apt-get update
help read:
-r do not allow backslashes to escape any characters
-s do not echo input coming from a terminal
I suggest you figure out all of the commands you need the script to run using SUDO, ensure the script is run by a special unprivileged user (e.g. scriptuser), and then edit /etc/sudoers to permit scriptuser to run those commands with NOPASSWD
As an example:
scriptuser ALL = NOPASSWD: /bin/kill, /usr/bin/othercommand, etc.
If you know the complete commands, including arguments, that's ideal (it means that an attacker that compromises the scriptuser account can only run those specific commands as root)
Sudo has a lot of options configurable in /etc/sudoers. If you man sudoers , you should see all of them. Forewarning: This man page is very hard to understand. Find examples. Test them. Ask on StackExchange.

Forcing usermod with running program

I've been looking for a way to force usermod to modify the password/group/... files despite the user being in use.
What I do get now is this:
!! Failed to execute 'usermod --home '...' --password '...' --shell '/bin/false' 'zabbix' 2>&1':
usermod: user zabbix is currently used by process 518
I know that for being secure I need to restart the service. But this is done within a setup script. I am restarting all services at the end.
Is there any way to say --force? (well, except for modifying all necessary files.)
Thanks
If you can get root rights via sudo and are confident enough to change system files using vi then I would change the files manually.
Only a few things need to be changed in
- /etc/passwd
here you could change UID, GID, Homedirectory, Shell ...
- /etc/group
here you might need to change UID/GID as well for the username if there was a change
The File /etc/shadow will be changed automatically when using passwd to set a new password. This you can directly perform if you are root: "passwd username"
You can run usermod in a separate user namespace (with a recent enough linux), but you need to map the root user to root (otherwise you won't have permissions to modify /etc/passwd).
I.e. something like this:
unshare --user --map-root-user usermod ...
Now usermod won't find the processes running with the uid of user you are modifying.
You probably won't be able to modify the root user itself with this.

How can i run a sudo command in Bash script?

I want to run the following sample bash script which needs sudo password for a command
#!/bin/bash
kinit #needs sudo password
vi hello.txt
while running the above script it is asking for password.
How can i pass the username and password in the command itself or is there any better way i can skip passing my password in the script ?
TL;DR
You can't—at least, not the way you think.
Longer Answer with Alternatives
You have a couple of options:
Authenticate interactively with sudo before running your script, e.g. sudo -v. The credentials will be temporarily cached, giving you time to run your script.
Add a specific command such as /usr/lib/klibc/bin/kinit to your sudoers file with the NOPASSWD option. See sudoers(5) and and visudo(8) for syntax.
Use gksudo(1) or kdesu(1) with the appropriate keyring to cache your credentials if you're using a desktop environment.
One or more of these will definitely get you where you want to go—just not the way you wanted to get there.
So if you have access to your full system, you can change your sudoers file to allow certain sudo commands to be run w/o a password.
On the command line run visudo
Find your user and change the line to look something like this:
pi ALL=(ALL) NOPASSWD: /path/to/kinit, /path/to/another/command
That should do it. Give it another shot!
Hope that helps
You shouldn't pass username and password. This is not secure and it is not going to work if the password is changed.
You can use this:
gksudo kinit # This is going to open a dialog asking for the password.
#sudo kinit # or this if you want to type your password in the terminal
vi hello.txt
Or you can run your script under root. But note that vi is going to be ran as root as well, which means that it will probably create files that belong to root, that might be not what you want.

In a bash script executed on boot, how do I get the username of the user just logged-in?

I need to execute a bash script on boot.
To do so I created a file
/etc/init.d/blah
I edited it and added the following lines
#! /bin/sh
# /etc/init.d/blah
touch '/var/lock/blah'
username1=$(id -n -u)
username2=$(whoami)
touch '/var/lock/1'${username1}
touch '/var/lock/2'${username2}
exit 0
The script is execute with root privileges (which is what I need because I have to use mount inside this script) .. but the problem is that I also need to know the username of the user who has just logged-in beacuse my goal is to mount a certain folder to a certain mount-point depending on the username, like
mount -o bind /home/USERNAME/mount-point /media/data/home/USERNAME/to-be-mounted
Going back to the boot script, if I do
sudo update-rc.d blah defaults
and then reboot and log-in with my username (let's say john) both ways to get username in my script produce root in fact I've got 3 files
/var/lock/blah
/var/lock/1root
/var/lock/2root
So, how can I get the username of the user who just logged-in? (john in my example)
EDITED:
I solved in this way:
1. I created a .desktop file for each user I need to perform automount on boot to autostart a script on boot (I'm on LXDE) and put it on /home/{username}/.config/autostart
[Desktop Entry]
Type=Application
Exec=bash "/path/to/mount-bind.sh"
2. I stored in that path a bash script called mount-bind.sh and made it executable:
#!/bin/bash
_username=$1
if [[ -z "${_username}" ]]; then
_username="$(id -u -n)"
fi
mkdir -p "/home/${_username}/mount-folder"
sudo mount -o bind "/media/data/home/${_username}/mount-folder" "/home/${_username}/mount-folder"
exit 0
3. I added the following line to /etc/sudoers
%nopwd ALL=(ALL) NOPASSWD: /bin/mount
4. I created the nopwd group and added to it all the users I need
In his way after login I can mount the path under the user home.
Problem with this method is that I have to create the desktop file for each new user and add him/her to nopwd, but it works.
Any further improvement is welcome! :)
I think you should move from a boot time init script to a script executed at login time under the logged-in user. To allow this, you should look into ways to allow your users to execute the mount command you need. Depending on what you are trying to achieve, one of the following methods may help you:
Assuming you are on Linux or some other UNIX with a similar feature, add the mountpoint to /etc/fstab with the user option, allowing normal users to mount the entry.
Execute mount through sudo with a suitably narrow sudoers configuration as to not allow users to execute any mount commands.
Write a suid-root program in c which executes the required mount commands when called. This however is very tricky to get right without creating gaping security holes.
Login does not happen at boot time. You cannot foretell which user is going to log in when booting.
Try Exporting the logindetails and use it.
export username2=$(whoami)

Want execute only shell script

I wrote a shell script to hook into a password protected database. A couple of others want to use the same shell script to share the database access, but I don't want to expose the password that is being used. Is there a way to lock the script so that no one can read it and only execute it? It'd also be ideal for them to enter their sudo password to run the script
Is there a way to lock the script so that no one can read it and only
execute it? It'd also be ideal for them to enter their sudo password
to run the script
Sure. Let's say the script containing the credentials is /usr/local/bin/myscript. Make this file owned by a privileged user. Let's say we have a user named "credentials":
# chown credentials /usr/local/bin/myscript
# chmod 700 /usr/local/bin/myscript
Now only the credentials user can read and execute this script.
Create another script /usr/local/bin/mywrapper that looks like this:
#!/bin/sh
exec sudo -u credentials /usr/local/bin/myscript
And create the appropriate /etc/sudoers entry:
auser ALL=(credentials) /usr/local/bin/myscript
So now, user auser runs "mywrapper". This in turn uses sudo to call the real script, which will prompt auser for their password.
I think this does everything you want. We use a mechanism very much like this at my office to protect credentials (in our case, ssh private keys).
In order to execute a shell script, you have to be able to read it. There are a couple of things you could do:
Who administers this database? Could the users get their own passwords for read only access? That would be ideal because it could limit their access to a small subset of the database.
If they have to have sudo access to run this script, maybe it's possible to remove the password out of the file and into a file that has 600 permissions set. The problem is that this could leak. For example, what if they run the script with set -xv? Then, they could see the password as the script executes.
Can you create a subset of data they might be interested in outside of the database? Then, have your script access that?
Or, you might want to take a look at several read-only modules in Perl. I'm thinking something like Acme::EyeDrops or Acme::Bleach which remove all those unsightly letters and numbers from your Perl script. (And I wonder why Python programmers say Perl is unreadable?)

Resources