sudo -u flawed file permissions - linux

I am using Bash on Lubuntu 16.04. LTS, but I'm not sure if this matters much for this question.
I noticed, that when I create a file as standard user, the file has 664 permissions. But when I am root and execute the same command for the same user via the -u argument, it has 644 permissions, so the write permissions for the group are missing.
I suppose this to be a flaw, since the sudo manpages clearly state:
-u user, --user=user
Run the command as a user other than the default target user (usually root). The user may be either a user name or a
numeric user ID (UID) prefixed with the ‘#’ character (e.g. #0 for UID 0). When running commands as a UID, many
shells require that the ‘#’ be escaped with a backslash (‘\’). Some security policies may restrict UIDs to those
listed in the password database. The sudoers policy allows UIDs that are not in the password database as long as the
targetpw option is not set. Other security policies may not support this.
Now that I know that the -u argument's behavior differs from the behavior that has to be expected, my question is:
How can I make sure, that a command that is started in a root shell gets executed exactly as it would be executed from another user's shell?
Remark: I know that I could fix this one problem by tinkering with the umask, but this won't guarantee me that the behavior doesn't differ in an arbitrary amount of other cases.

It looks like the umask depends on whether the shell is interactive:
$ umask
0002
$ sudo -u $USER bash -c umask
0022
$ sudo -u $USER bash -ic umask
0002
This appears to be from from /etc/bashrc, which applies umask 002 only if
it's not a login shell,
the UID is greater than or equal to 200, and
the username is equal to the group name,
or from /etc/profile, which applies umask 002 if the last two criteria are met. I'm not sure if something else is overriding this, because shopt login_shell prints the same whether the shell is interactive or not, and the UID is also the same.
You can get the user's default shell thusly:
$ getent passwd $USER | cut --delimiter=: --fields=7
/bin/bash
Combining them:
$ sudo -u $USER $(getent passwd $USER | cut --delimiter=: --fields=7) -ic umask
0002

A nice and clean solution that shows the expected behavior is this:
sudo su <username> -c '<any commands>'

Related

How to check for privileges to use useradd and groupadd for creation of users and groups

How can I check if the current user has all privileges to use useradd and groupadd for creation of users and groups?
I don't want to request root privileges (e.g. requireing to be root or calling sudo) for my bash script unnecessarily. Instead I just want to ensure that the privileges are there to just use those commands.
The commands:
$ ls -l $(which useradd) $(which groupadd)
-rwxr-xr-x 1 root root 93136 Mai 28 2020 /usr/sbin/groupadd
-rwxr-xr-x 1 root root 147160 Mai 28 2020 /usr/sbin/useradd
As useradd and groupadd commands need some extra priviledges to run, you can setup access to sudo for specific commands like useradd and groupadd like below :-
Please go through it once, it will make most of the things clear to you
Controlling Access To sudo
The /etc/sudoers file configures the programs that users can access using sudo, along with whether or not a password will be needed.
The system administrator adds users to this file using the /usr/sbin/visudo command. Each non-comment line in the file has two parts:
A username ("<USER_NAME>"), or a group name ("%<GROUP_NAME>").
A list of machine names where a program may be run, or the keyword ALL. Following an equal sign (=), a list of user identities the command may be run as, enclosed in round brackets (parenthesis); the wildcard ALL may also appear. Finally, a list of applications that may be run as the named users; the keyword ALL is a wildcard.
The following examples should help make this clear:
<USER_NAME> ALL=(ALL) ALL
# User <USER_NAME> can execute any command as any user, but must know the password to the <USER_NAME> account.
<USER_NAME> ALL=(root) shutdown
# User <USER_NAME> can execute only command shutdown, but must know the password to the <USER_NAME> account.
<USER_NAME> ALL=(root) NOPASSWD: /usr/bin/id
# User <USER_NAME> can execute only the application /usr/bin/id; no password will be needed.
<USER_NAME> ALL=() NOPASSWD: /usr/bin/id
# User <USER_NAME> can execute only the application /usr/bin/id; no password will be needed.
Once the system administrator has entered the necessary setup into the /etc/sudoers file, users can safely access privileged system resources and activities like this:
$ sudo useradd username
No awkward quoting on the command line, just prefix the command you want with the word sudo. If you want to run the command as a user other than root, just add the -u username switch:
$ sudo -u <USER_NAME> useradd username
There will be a log entry written to the /var/log/secure file to show who did the deed.
Of course, the sysadmin can configure sudo not to request a password. In this case, the command is immediately executed although the audit trail entry will still be written.
Reference :- Sudo Tutorial
Please reach in the comments section for any help
Will be glad to help !!!
Assuming that you need root or sudo to add new users (same for group), you can check if the user has sudo rights, by checking if he is in the corresponding groups.
getent group sudo // shows all users in groupd sudo
Dont know what system/distro you are on - but on arch for example sudoers are in group wheel...
On Linux debian-linux 5.10.0-6-amd64 #1 SMP Debian 5.10.28-1 (2021-04-09) x86_64 GNU/Linux,
you can try this way in your script.
groupadd 2>/dev/null ; if test $? -eq 2 ; then echo ok ; else echo bad ; fi
If you can access groupadd or useradd, the return value is 2 because there is missings arguments.
If you can't acess groupadd or useradd, the return value is 127.

How to demand root privileges in a shell script? [duplicate]

This question already has answers here:
How to check if running as root in a bash script
(21 answers)
Closed 7 years ago.
Say you have a shell script that could potentially require root privileges. You don't want to force the user to run it as sudo. However, if it does require that privilege, you want to prompt the user to enter their password, rather than complaining and forcing them to re-enter the command with sudo.
How would you go about doing this in a Bash script? sudo true seems to work, but it feels like a hack. Is there a better way?
Here's what I often do. This is loose pseudo-code but should give you the idea:
# myscript -- possibly execute as sudo
if (passed -e option) then
read variables from envfile
else
...
need_root = ...
# set variables ...
if ($need_root && $uid != 0) then
env [or whatever] > /tmp/envfile
exec sudo myscript -e/tmp/envfile ...
fi
fi
# stuff to execute as root [or not] ...
The command
sudo -nv
checks whether the user has current sudo credentials (-v), but will fail rather than prompting if access has expired (-n).
So this:
if sudo -nv 2>/dev/null && sudo -v ; then
sudo whoami
else
echo No access
fi
will check whether the user's sudo credentials are current, and prompt for a password only if they're not.
There is a possible race condition: the user's credentials could expire just after the check.
As ghoti points out in a comment, this may not work if the sudoers file is set up to allow only certain commands to be executed. For that and other reasons, be sure to check whether each sudo command succeeded or failed.
If your plan is to use sudo for privilege escalation, one wrinkle you may have to deal with is that that sudo can be set up to permit root access to some commands and not others. For example let's imagine you've got a server that runs VirtualBox, with different people managing the applications than are managing the OS. Your sudoers file might contain something like the following:
Cmnd_Alias SAFE = /bin/true, /bin/false, /usr/bin/id, /usr/bin/who*
Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/halt, /sbin/reboot
Cmnd_Alias SU = /bin/su, /usr/bin/vi*, /usr/sbin/visudo
Cmnd_Alias SHELLS = /bin/sh, /bin/bash, /bin/csh, /bin/tcsh
Cmnd_Alias VBOX = /usr/bin/VBoxManage
%wheel ALL=(ALL) ALL, !SU, !SHELLS, !SHUTDOWN
%staff ALL=(ALL) !SU, !SHELLS, NOPASSWD: SAFE
%operator ALL=(ALL) SAFE, SHUTDOWN
%vboxusers ALL=(ALL) NOPASSWD: VBOX
In this case, a member of the vboxusers unix group will always get a successful response to a sudo -nv, because of the existence of the NOPASSWD entry for that group. But a member of that group running any other command than VBoxManage will get a password challenge and a security warning.
So you need to determine whether the command you need to run can be run without a password prompt. If you don't know how sudo is configured on the system where your script is running, the canonical test is to run the command. Running sudo -nv will only tell you whether you are authenticated; it won't tell you what commands you have access to.
That said, if you can safely rely on a sudo configuration where, say, membership in wheel group gives you access to all commands, for example with:
%wheel ALL=(ALL) ALL
then you can use sudo -nv to test for escalation capabilities. But your script might have some things that it runs as root, and some things it doesn't. You might also want to consider other tools besides sudo for privilege escalation.
One strategy might be to set a variable to preface commands if the need is there, but leave the variable blank if you're already root (i.e. running the entire script inside sudo).
if ! which sudo >/dev/null 2>/dev/null; then
PM_SU_CMD="su - root -c"
elif sudo -nv 2>/dev/null; then
PM_SU_CMD="sudo"
else
echo "ERROR: I can't get root." >&2
exit 1
fi
Of course, if we are already root, unset this to avoid potential conflict:
[ `ps -o uid= $$` -eq 0 ] && unset PM_SU_CMD
(Note that this is a query of the system's process table; we don't want to rely on the shell's environment, because that can be spoofed.)
Then, certain system utilities might be made more easily available using functions:
# Superuser versions for commands that need root privileges
find_s () { $PM_SU_CMD "/usr/bin/find $*"; }
mkdir_s () { $PM_SU_CMD "/bin/mkdir -p $1"; }
rm_s () { $PM_SU_CMD "/bin/rm $*"; }
Then within your script, you'd simply use the _s version of things that need to be run with root privileges.
This is of course by no means the only way to solve this problem.

Run script as another user on Linux

I am trying to create a Linux terminal menu by way of a simple script. Within the script it will have some commands that will submit a job (a shell script for example) as another user without password prompt.
I was able to find the following post and this worked. how to run script as another user without password
However, there was one side affect. It appears the user can run other scripts in that users folder which I don't want.
Any suggestions/help welcome.
For the sake of this. Here is what I have:
Username temp1, which is the user that will be running the menu.
uid=1001(temp1), gid=1001(temp1), groups=1001(temp1)
Username wayne, which is the user that the script must be submitted as to run the job
uid=1000(wayne), gid=1000(wayne),groups=1000(wayne),4(adm),24(cdrom),27(sudo),30(dip)...
Script script1.sh, script2.sh owned by wayne.
-rwxr-xr-x script1.sh
-rwxr-xr-x script2.sh
If I try to go to /home/wayne as temp1 user I get permission denied (expected)
I set the scripts to chmod 700 for wayne. So technically no one can run them other than wayne.
I have edited sudo file and have the following entry:
temp1 ALL(wayne) NOPASSWD: /home/wayne/script1.sh
When I run command su -c "/home/wayne/script1.sh" -s /bin/sh wayne the script runs (as expected)
When I run command su -c "/home/wayne/script2.sh" -s /bin/sh wayne the script runs (not expected).
Any ideas?
The answer is change from su to sudo.
su is primarily for switching users, while sudo is for executing commands as other users. The -u flag lets you specify which user to execute the command as:
sudo -u wayne '/home/wayne/script2.sh'
gives Sorry user is not allowed to execute
Solution: In order to run commands/scripts as another user on linux/unix you need sudo permission and run the following formula:
sudo -H -u <user> bash -c '<some-command>'
For example:
sudo -H -u wayne bash -c 'echo "user:$USER|home:$HOME|action:run_script"; ./home/wayne/script.sh'
from Documentation:
sudo allows a permitted user to execute a command as the superuser or
another user, as specified by the security policy.
-H The -H (HOME) option requests that the security policy set
the HOME environment variable to the home directory of the
target user (root by default) as specified by the password
database. Depending on the policy, this may be the default
behavior.
-u user The -u (user) option causes sudo to run the specified
command as a user other than root. To specify a uid
instead of a user name, use #uid. When running commands as
a uid, many shells require that the '#' be escaped with a
backslash ('\'). Security policies may restrict uids to
those listed in the password database. The sudoers policy
allows uids that are not in the password database as long
as the targetpw option is not set. Other security policies
may not support this.

Why this linux command can affect the environment variables?

When I changed my current user to admin using
sudo su admin
I found that the environment variable changed too. What I intend to do is to change my user to admin with the env not changed.
Then I found a command as follows:
sudo bash -c "su - admin"
This command does indeed what I want, but I googled about bash -c, with no clue to why this command can do that for me. Could anyone give me a clear explanation? Thanks a lot.
first you should read the sudo manpage and set theses options in the /etc/sudoers file or you can do it interactively (see second below).
default sudoers file may not preserve the existing $USER environment unless you set the config options to do so. You'll want to read up on env_reset because depending on your OS distribution the sudo config will be different in most cases.
I dont mean to be terse but I am on a mobile device..
I do not recommend using sudo su .. for anything. whomever is sharing sudo su with the public is a newb, and you can accomplish the same cleaner with just sudo.
with your example whats happining is you are starting a subshell owned by the original user ("not admin") . you are starting the subshell with -c "string" sudo has the equivelant of the shell's -c using -s which either reads the shell from the arg passed to -s or the shell defined in the passwd file.
second you should use:
$ sudo -u admin -E -s
much cleaner right ? :)
-u sets the user, obviously
-s we just explained
-E preserves the orig user env
see for yourself just
$ echo $HOME # should show the original users /home/orig_user
$ env
your original env is preserved with none of that sudo su ugliness.
if you were interested in simulating a users login without preserving the env..
$ sudo -u user -i
or for root:
Might require -E depending on distro sudoers file
$ sudo -s
or
$ sudo -i
-i simulates the login and uses the users env.
hopefully this helps and someone will kindly format it to be more readable since im on my mobile.
bash with -c argument defines below.
-c string
If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.
Thanks & Regards,
Alok

How to pipe a variable as password in a bash script when requiring root access [duplicate]

I'm writing a UNIX shell function that is going to execute a command that will prompt the user for a password. I want to hard-code the password into the script and provide it to the command. I've tried piping the password into the command like this:
function() {
echo "password" | command
}
This may not work for some commands as the command may flush the input buffer before prompting for the password.
I've also tried redirecting standard input to a file containing the password like this, but that doesn't work either:
function() {
echo "password" > pass.tmp
command < pass.tmp
rm pass.tmp
}
I know that some commands allow for the password to be provided as an argument, but I'd rather go through standard input.
I'm looking for a quick and dirty way of piping a password into a command in bash.
How to use autoexpect to pipe a password into a command:
These steps are illustrated with an Ubuntu 12.10 desktop. The exact commands for your distribution may be slightly different.
This is dangerous because you risk exposing whatever password you use to anyone who can read the autoexpect script file.
DO NOT expose your root password or power user passwords by piping them through expect like this. Root kits WILL find this in an instant and your box is owned.
EXPECT spawns a process, reads text that comes in then sends text predefined in the script file.
Make sure you have expect and autoexpect installed:
sudo apt-get install expect
sudo apt-get install expect-dev
Read up on it:
man expect
man autoexpect
Go to your home directory:
cd /home/el
User el cannot chown a file to root and must enter a password:
touch testfile.txt
sudo chown root:root testfile.txt
[enter password to authorize the changing of the owner]
This is the password entry we want to automate. Restart the terminal to ensure that sudo asks us for the password again. Go to /home/el again and do this:
touch myfile.txt
autoexpect -f my_test_expect.exp sudo chown root:root myfile.txt
[enter password which authorizes the chown to root]
autoexpect done, file is my_test_expect.exp
You have created my_test_expect.exp file. Your super secret password is stored plaintext in this file. This should make you VERY uncomfortable. Mitigate some discomfort by restricting permissions and ownership as much as possible:
sudo chown el my_test_expect.exp //make el the owner.
sudo chmod 700 my_test_expect.exp //make file only readable by el.
You see these sorts of commands at the bottom of my_test_expect.exp:
set timeout -1
spawn sudo chown root:root myfile.txt
match_max 100000
expect -exact "\[sudo\] password for el: "
send -- "YourPasswordStoredInPlaintext\r"
expect eof
You will need to verify that the above expect commands are appropriate. If the autoexpect script is being overly sensitive or not sensitive enough then it will hang. In this case it's acceptable because the expect is waiting for text that will always arrive.
Run the expect script as user el:
expect my_test_expect.exp
spawn sudo chown root:root myfile.txt
[sudo] password for el:
The password contained in my_test_expect.exp was piped into a chown to root by user el. To see if the password was accepted, look at myfile.txt:
ls -l
-rw-r--r-- 1 root root 0 Dec 2 14:48 myfile.txt
It worked because it is root, and el never entered a password. If you expose your root, sudo, or power user password with this script, then acquiring root on your box will be easy. Such is the penalty for a security system that lets everybody in no questions asked.
Take a look at autoexpect (decent tutorial HERE). It's about as quick-and-dirty as you can get without resorting to trickery.
You can use the -S flag to read from std input. Find below an example:
function shutd()
{
echo "mySuperSecurePassword" | sudo -S shutdown -h now
}
Secure commands will not allow this, and rightly so, I'm afraid - it's a security hole you could drive a truck through.
If your command does not allow it using input redirection, or a command-line parameter, or a configuration file, then you're going to have to resort to serious trickery.
Some applications will actually open up /dev/tty to ensure you will have a hard time defeating security. You can get around them by temporarily taking over /dev/tty (creating your own as a pipe, for example) but this requires serious privileges and even it can be defeated.
with read
Here's an example that uses read to get the password and store it in the variable pass. Then, 7z uses the password to create an encrypted archive:
read -s -p "Enter password: " pass && 7z a archive.zip a_file -p"$pass"; unset pass
But be aware that the password can easily be sniffed.
Programs that prompt for passwords usually set the tty into "raw" mode, and read input directly from the tty. If you spawn the subprocess in a pty you can make that work. That is what Expect does...
Simply use :
echo "password" | sudo -S mount -t vfat /dev/sda1 /media/usb/;
if [ $? -eq 0 ]; then
echo -e '[ ok ] Usb key mounted'
else
echo -e '[warn] The USB key is not mounted'
fi
This code is working for me, and its in /etc/init.d/myscriptbash.sh
That's a really insecure idea, but:
Using the passwd command from within a shell script

Resources