How to allow a normal user to kill a certain root application in visudo with no password - linux

I wanna allow a normal user to kill a certain application which is started by root user.
In visudo:
I added a line like this:
normal_user ALL=(ALL) NOPASSWD: /usr/bin/kill $(ps aux | grep 'target_application' | awk '{print $2}')
But after save it and execute the following command as normal_user, I still get the prompt for root password:
sudo /usr/bin/kill $(ps aux | grep 'target_application' | awk '{print $2}')
What should I do then? Thanks a lot!

sudo will not interpret the command as a shell script to execute. Therefore you have said that this literal command can be run as normal_user:
/usr/bin/kill $(ps aux | grep 'target_application' | awk '{print $2}')
However since the shell will interpret the stuff in the $(...) before sudo is called on it, the command you are running looks more like this:
sudo /usr/bin/kill 1234
So it doesn't let you use it.
As fedorqui suggested, you should write a script that kills the user and then give normal_user the right to run that script (make sure they don't have write access to the script or its directory though).
kill_target_application.sh:
#!/bin/sh
/usr/bin/kill $(ps aux | grep 'target_application' | awk '{print $2}')
Use this command to allow users to execute or read the script, but not modify it:
chown root:root <filename>
chmod 755 <filename>
The give (r)ead and e(x)ecute permissions for all users, but only root can modify it. Also ensure that the user does not have write permissions for the directory or any of its parent directories. Read the chown and chmod man pages before doing this if you aren't familiar with these utilities.
visudo entry:
normal_user ALL=(ALL) NOPASSWD: /path/to/kill_target_application.sh
You should probably use "killall" instead of this complicated ps | grep option. Or at least look into pgrep.
Also, this really sounds like a job for an init script.

Related

Why can't this script execute the other script

This script looks for all users that have the string RECHERCHE inside them. I tried running it in sudo and it worked, but then stopped at line 8 (permission denied). Even when removing the sudo from the script, this issue still happens.
#!/bin/bash
#challenge : user search and permission rewriting
echo -n "Enter string to search : "
read RECHERCHE
echo $(cat /etc/passwd | grep "/home" | cut -d: -f5 | grep -i "$RECHERCHE" | sed s/,//g)
echo "Changing permissions"
export RECHERCHE
sudo ./challenge2 $(/etc/passwd) &
The second script then changes permissions of each file belonging to each user that RECHERCHE found, in the background. If you could help me figure out what this isn't doing right, it would be of great service. I
#!/bin/bash
while read line
do
if [-z "$(grep "/home" | cut -d: -f5 | grep -i "$RECHERCHE")" ]
then
user=$(cut -f: -f1)
file=$(find / -user $(user))
if [$(stat -c %a file) >= 700]
then
chmod 700 file 2>> /home/$(user)/challenge.log
fi
if [$(stat -c %a file) < 600]
then
chmod 600 file 2>> /home/$(user)/challenge.log
fi
umask 177 2>> /home/$(user)/challenge.log
fi
done
I have to idea what I'm doing.
the $(...) syntax means command substitution, that is: it will be replaced by the output of the command within the paranthesis.
since /etc/passwd is no command but just a text-file, you cannot execute it.
so if you want to pass the contents of /etc/passwd to your script, you would just call it:
./challenge2 < /etc/passwd
or, if you need special permissions to read the file, something like
sudo cat /etc/passwd | ./challenge2
also in your challenge2 script, you are using $(user) which is wrong as you really only want to expand the user variable: use curly braces for this, like ${user}
/etc/passwd?
not what you were asking, but you probably should not read /etc/passwd directly anyhow.
if you want to get a list of users, use the following command:
$ getent passwd
this will probably give you more users than those stored in /etc/passwd, as your system might use other PAM backends (ldap,...)

Command wont run in script

I am trying to run a command in a shell script but it is not working.
Out side of the script in the shell I can run the following command on the needed host. The file is created with the correct information inside.
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
When the command is run in my script I first ssh over then run the command but I get the following error.
[batch#testserver01 bin]$ checkP.sh
Testserver02
/usr/local/bin/checkP.sh: line 7: /tmp/expirelist.txt: Permission denied
Here is a part of the script. I have tried using ssh -o
#!/bin/bash
for SERVER in `cat /admin/lists/testlist`
do
echo $SERVER
ssh $SERVER sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
...
What is causing the Permission denied error?
Don't use hardcoded temporary filenames -- when you do, it means that if one user (say, your development account) already ran this script and left a file named /tmp/expirelist.txt behind, no other user can run the same script.
tempfile=$(mktemp -t expirelist.XXXXXX)
ssh "$SERVER" sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d >"$tempfile"
By using mktemp, you guarantee that each invocation will use a new, distinct, and previously-nonexisting temporary file, preventing any chance of conflict.
By the way -- if you want the file to be created on the remote system rather than the local system, you'd want to do this instead:
ssh "$SERVER" <<'EOF'
tempfile=$(mktemp -t expirelist.XXXXXX)
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d >"$tempfile"
EOF
I'm not sure about this, but you could be running into an issue with having the 'sudo' within your script. You could try removing the 'sudo' from the script, and running it like this:
$ sudo checkP.sh

Why does the output differ when executed from a shell script?

According to this post, I run this from the command line:
USER_HOME=$(getent passwd $SUDO_USER | cut -d: -f6)
and get the following output:
/root
/usr/sbin
/bin
/dev
/bin
/usr/games
/var/cache/man
/var/spool/lpd
/var/mail
/var/spool/news
/var/spool/uucp
/bin
/var/www
/var/backups
/var/list
/var/run/ircd
/var/lib/gnats
/nonexistent
/var/lib/libuuid
/home/user
/var/run/vboxadd
/var/lib/puppet
/var/run/sshd
When I run this in a script (as sudo, which is the point of the whole thing --- as sudo, ~ expands to /root):
USER_HOME=$(getent passwd $SUDO_USER | cut -d: -f6)
echo $USER_HOME
I get my correct path /home/user.
Why can I not invoke my function manually to get the same output?
Because when not using sudo, $SUDO_USER is not set and you get the output of getent passwd without further argument, which lists all users. The cut then extracts the home directory part.
Replace $SUDO_USER with $USER when not running with sudo.
Note that using getent passwd ${SUDO_USER:-$USER} should work in both cases.

How do I get "awk" to work correctly within a "su -c" command?

I'm running a script at the end of a Jenkins build to restart Tomcat. Tomcat's shutdown.sh script is widely known not to work all in many instances and so my script is supposed to capture the PID of the Tomcat process and then attempt to manually shut it down. Here is the command I'm using to capture the PID:
ps -ef | grep Bootstrap | grep -v grep | awk '{print $2}' > tomcat.pid
The output when manually runs retrieves the PID perfectly. During the Jenkins build I have to switch users to run the command. I'm using "su user -c 'commands'" like this:
su user -c "ps -ef | grep Bootstrap | grep -v grep | awk '{print $2}' > tomcat.pid"
Whenever I do this however, the "awk" portion doesn't seem to be working. Instead of just retrieving the PID, it's capturing the entire process information. Why is this? How can I fix the command?
The issue is that $2 is being processed by the original shell before being sent to the new user. Since the value of $2 in the shell is blank, the awk command at the target shell essentially becomes awk {print }. To fix it, you just escape the $2:
su user -c "pushd $TOMCAT_HOME;ps -ef | grep Bootstrap | grep -v grep | awk '{print \$2}' > $TOMCAT_HOME/bin/tomcat.pid"
Note that you want the $TOMCAT_HOME to be processed by the original shell so that it's value is set properly.
You don't need the pushd command as you can replace the awk command with:
cut -d\ -f2
Note: two 2 spaces between -d\ and -f2

Bash Script, Kill process by pulling from PID file

This is what I have right now in the bash script:
ps aux | grep glassfish | grep domain1 | gawk '{print $2}' | xargs kill -9
The problem with this is that if someone else is logged in and pulling something related to glassfish, it wil pull that PID as well. Thus resulting in killing the wrong PID.
So My question is how do I fix what I have to only pull the correct PID, and how do I rewrite it to pull the PID from the PID file that glassfish generates.
Edit the script that starts glassfish and place something like echo $$ > /path/to/PID-file (this can contain ~ for home directory or some other mechanism like $USER to make user specific) on the line immediately following the line starting the process. You can then kill the correct process using kill $(cat /path/to/PID-file).
ps aux | grep ^$USER | grep glassfish | grep domain1 | gawk '{print $2}' | xargs kill -9
Below i did mistake with ps switches, so above grep should be fine.
ah it is not working, ps could be use like this ps -ao pid,tty,comm -u $USER, this grep above should be fine ...
someone else is logged in ...
If so, add switch -u
ps aux -u $USER | grep glassfish | grep domain1 | gawk '{print $2}' | xargs kill -9
$USER is user name that will be selected and listed, by default should be already set in OS environment. Multiple users could be selected by comma ps aux -u root,$USER
Take a note: If there is no specific username in the system, ps will throw ERROR: User name does not exist.
Read man ps for more.
-u userlist Select by effective user ID (EUID) or name.
This selects the processes whose effective user name or ID is in userlist. The effective user ID describes the user whose
file access permissions are used by the process (see geteuid(2)).
Identical
to U and --user.

Resources