This is about me being stressed by playing the game "type a command and remember to prepend sudo or your fingers will get slapped".
I am wondering if it is possible somehow to configure my Linux system or shell such that when I forget to type e.g. "sudo apt-get install emacs", instead of just telling me that I did something wrong, gksudo would get launched, allowing me to acknowledge my credentials and get on moving. Just like UAC does on windows.
Googling hasn't helped me yet..
So is this possible? Did I miss something? Or am I asking for a square circle?
Edit 2010 July 25th: Thanks everyone for your interrest. Unfortunately, Daenyth and bmargulies answers and explanations are what I anticipated/feared since it was impossible for me to google-up a solution prior to submitting this question. I hope that some nice person will someday provide an effective solution for this.
BR,
Christian
Linux doesn't allow for this. Unlike Windows, where any program can launch a dialog box, and UAC is in the kernel, Linux programs aren't necessarily GUI-capable, and sudo is not, in this sense, in the kernel. A program cannot make a call to elevate privilege (unless it was launched with privilege to begin with and intentionally setuid'd down). sudo is a separate executable with setuid privilege, which checks for permission. If it likes what it sees, it forks the shell to execute the command line. This can't be turned inside out.
As suggested in other posts, you may be able to come up with some 'shell game' to arrange to run sudo for you for some enumerated list of commands, but that's all you are going to get.
You can do what you want with a preexec hook function, similar to the command-not-found package.
There's no way to do this given the current linux software stack. Additionally, MS has a patent on this behavior -- present a user interface identifying an account having a right to permit a task in response to the task being prohibited based on a user's current account not having that right.
I don't think this really works in a general way (automatically deciding which application needs admin rights). However you could make aliases like this for every application:
alias alias apt-get='gksudo apt-get'
If you now enter apt-get install firefox the gnome asks for the admin password. You can store the commands in ~./bashrc
You could use a shell script like the following:
#!/bin/bash
$#
if [ $? -ne 0 ]; then
sudo $# # or "gksudo $#"
fi
This will run a command given in the arguments with a sudo prefix if the command came back with a non-zero return code (i.e. if it failed).
Use it as in "SCRIPT_NAME apt-get install emacs" for example. You may save it somewhere in your $PATH and set it as an alias like this (if you saved it as do_sudo):
alias apt-get='do_sudo apt-get'
Edit: That does not work for programs like synaptic which do work for non-root users but will give them less privileges. However, if the application fails when invoked without root privileges (like apt-get does) this works fine.
In the case where you want to always run a command as root but might already be root, you can solve this by wrapping a little bash script around it:
#!/bin/bash
if [ $EUID = 0 ]; then
"$#"
else
gksudo "$#"
fi
If you call this something like alwaysroot.bash and place it in the right spot on your PATH, then you can call your other program like this:
alwaysroot.bash otherprogram -arguments...
It even handles arguments with spaces in correctly.
Related
RH6. Is it possible to issue, for example, a cd command in a running xterm process FROM a different process? I know the pid of the existing xterm proc. I actually want to "echo" a message first, and then cd. Something like...
echo "Your time in this workarea has expired. You are being sent home"
cd ~
It would be great if I could do this as a different user somehow (not the owner of the target proc) (I am not and cannot be root). But if that is not possible, perhaps having the target xterm owner create an executable which wraps these commands inside, and then setting the sticky bit on the executable might work when the 2nd proc goes to run it. Not sure if lint checking will catch this as some sort of foul.
I would just make this a comment, but I don't have enough reputation. But I think this might be on the right track:
https://serverfault.com/questions/178457/can-i-send-some-text-to-the-stdin-of-an-active-process-running-in-a-screen-sessi
I'm driven here by my weak Google-fu. I found this question to be extremely difficult to search.
I wrote a bash script that checks for package updates to my Debian Wheezy load. This is not a cron job. I want the user to be able to run the script manually whenever she suspects (via an email, for example) that package updates may be available and then be able to actually download and install same.
If the script is run and updates are found, I want the script to then ask the user for the root password, then open Aptitude, so the user can see what package updates are available.
I have the script running on several hosts, but on one of the hosts, I want to have the script alert me if the host does not currently have a network connection before checking for updates. For this, I use the "route" command, which requires root privileges to run. I don't, however, wish to put "route" into said host's sudoers file. So, on the particular host that I need network connectivity confirmation, I have referenced the script itself in that host's sudoers file:
booboo ALL = NOPASSWD: /home/booboo/Scripts/chk4updates.sh
Here is a look at an outline of what the script does:
host=$(hostname)
if [ $host = travel ] ; then
...check for a connection, using the "route" command...
fi
...check for package updates...
if [ ...updates are found... ] ; then
gksu aptitude
fi
For all of the non-problem hosts, if updates are found, I get the gksu window that asks for the root password so that "aptitude" can be opened. But, for the host named "travel", the script opens aptitude without asking for a root password. I don't want this to happen.
I've tried a few things, but nothing has worked for me. Do I need to modify the problem host's sudoers file, or can I add a command to the script that will give me my desired behavior? Something like:
...
...check for package updates...
if [ ...updates are found... ] ; then
if [ $host = travel ] ; then
...some command so that a root password is required to open aptitude...
else
gksu aptitude
fi
fi
TIA!
When you are root, you can switch to a regular user at any point with su.
if [ -z "$SUDO_USER" ]; then
gksudo aptitude
else
su -c 'gksudo aptitude' "$SUDO_USER"
fi
Your setup seems extremely brittle and convoluted, though. There really is no such thing as a safe sudo shell script. The requirement to not add route to the sudoers file seems suspicious. Is there really no way you can refactor this so that the special case is handled on travel somehow? Maybe write a wrapper for route which you can put in sudoers and which checks that it's called from the right script, for example.
However, I would actually go with ping instead of route -- after all, route only tells you whether the route is set up locally, but won't reveal if there is a connectivity problem to the outside world. Then the rest of your question is moot.
(Or maybe even use something like cron-apt and remove the whole problem completely.)
I'm trying to run a bash script when my EC2 instances start up. All I want to do is start up GlassFish when the server starts. The command I'm trying to run is:
sudo /glassfish3/bin/asadmin start-domain
Which works when I enter it manually.
I have tried adding this command in a couple places with no luck:
at the end of /etc/rc.local
at the end of /etc/rc.d/rc.local
created my own script in /etc/init.d/
I have given every script 777 permissions.
Anyone have any ideas on what I'm doing wrong?
Unless oddly configured, sudo wants authentication when run. It is normally meant to be run interactively.
Assuming that the script /glassfish3/bin/asadmin is owned by root, you can set its file permissions to 6755. This does what you probably meant sudo to do. Of course, it can also be dangerous and may be a security risk.
(#jcomeau_ictx is right, incidentally. You should check logs as he suggests.)
Update for the benefit of archival: The above answer fortunately seems to have solved the OP's immediate problem, so we'll leave it at that. However, since this answer will remain archived and others may look it up later, I should add more to it.
One can change the file permissions of any executable to 6755, but such is not always a good practice. The effect of such permissions is (a) to let anyone run the executable with (b) the full privileges of the executable's owner. Sometimes, this is exactly what you want, but see: in the OP's case, /glassfish3/bin/asadmin with such permissions can now be called by anybody, with any arguments, with full root privileges. If that is not what you want, then you must take some additional care.
Several ways of taking additional care are possible. One is as follows.
Leave the executable with file permissions 755.
Write and compile a small wrapper, a program which uses execv() of unistd.h to launch the executable.
If practicable, do not let the wrapper take any arguments; otherwise, let its arguments be as restricted and inflexible as they can be. Let the wrapper strictly control the arguments passed to the executable.
Let the wrapper be owned by root, but use chown to assign it a suitable group whose membership includes no users. You may prefer to start a new group for this purpose but, if you scan the /etc/group file on your system, you are not unlikely to find an already existing group that suits. For reference, you can list commands already belonging to special-purpose groups on your system by ls -l /bin /usr/bin | grep -vE '^([^[:space:]]+[[:space:]]+){2}(root[[:space:]]+){2}' or the like.
Give the wrapper file permissions 6754, thus making it nonexecutable except to the group in question.
Admit the calling script to the group, and give the calling script file permissions 2755.
If the calling script already belongs to a group, you can probably just use the same group throughout.
Several variations of the technique are possible, and it is unlikely that you will use exactly the one listed above, but if you read the manpage and/or info entry on the chown command and learn the details of file permissions, and if you experiment a little, you should be able to craft a solution that works for you without posing a security risk.
Most probably it's JAVA_HOME issue, try using sudo -i, here is my working init script:
#!/bin/bash
# description: Glassfish Start Stop Restart
# processname: glassfish
# chkconfig: - 95 80
DOMAIN=domain555
GF_HOME=/opt/glassfish3
DOMAIN_DIR=/home/glassfish/domains
RUN_AS=glassfish
CMD_START="$GF_HOME/bin/asadmin start-domain --domaindir $DOMAIN_DIR"
CMD_STOP="$GF_HOME/bin/asadmin stop-domain --domaindir $DOMAIN_DIR"
function start() {
sudo -u $RUN_AS -i $CMD_START $DOMAIN
}
function stop() {
sudo -u $RUN_AS -i $CMD_STOP $DOMAIN
}
case $1 in
start)
start;
;;
stop)
stop;
;;
restart)
stop;
start;
;;
esac
exit 0
JAVA_HOME and PATH should be set in user's .bashrc or .bash_profile
I feel silly asking this...
I am not an expert on shell scripting, but I am finally in enough of a sysadmin role that I want to do this correctly.
I have a production server that hosts a webapp. Here is my routine.
1 - ssh to server
2 - cd django_src/django_apps/team_proj
3 - svn update
4 - sudo /etc/init.d/apache2 restart
5 - logout
I want to create a shell script for steps 2,3,4.
I can do this, but it will be a very plain and simple bash script simply containing the actual commands I type at the command line.
My question: What is the best way to script this kind of repetitive procedure in bash (Linux, Ubuntu) for a remote server?
Thanks!
The best way is simply as you suggest. Some things you should do for your script would be:
put set -e at the top of the script (after the shebang). This will cause your script to stop if any of the commands fail. So if it cannot cd to the directory, it will not run svn update or restart apache. You can do this programmatically by putting || exit 0 after each command, but if that's all you're doing, you may as well use set -e
Use full paths in your script. Do not assume the directory that the script is run from. In this specific case, the cd command has a relative path. Use a full (absolute) path, or use an environment variable like $HOME.
You may want to set up sudo so that it can run the command without asking for a password. This makes your script non-interactive which means it can be run in the background and from cron jobs and such.
As time goes by, you may add features and take command line arguments to parameterise the script. But don't bother doing this up front. Just evolve your scripts as you need.
There is nothing wrong with a simple bash script simply containing the actual commands you type at the command line. Don't make it more complicated than necessary.
I'd setup a cron job doing that automatically.
Since you're using python, check out fabric - you can use it to automate these kind of tasks. First install fabric:
$ sudo easy_install fabric
then write your fabric script:
from __future__ import with_statement
from fabric.api import *
def svnupdate():
with cd('django_src/django_apps/team_proj'):
run('svn update')
sudo('/etc/init.d/apache2 restart')
Save as fabfile.py, then run using the fab command:
$ fab -H hostname svnupdate
Tell me that's not cool! :-)
you can do this with the shell (bash,ksh,zsh + ssh + tools), or programming languages such as Python,Perl(Ruby or PHP or Java) etc, basically a language that supports SSH protocol and operating system functions. The "best" one is the one that you are more comfortable and have knowledge in. If you are doing sysadmin, the shell is the closest thing you can use. Then after you have done your script, you can use the crontab (cron) , or the at command to schedule your task. check their man page for more information
You can easily do the above using bash/Bourne etc.
However I would take the time and effort to learn Perl (or some similarly powerful scripting language). Why ?
the language constructs are much more powerful
there are no end of libraries to interface to the systems/features you want to script
because of the library support, you won't have to spawn off different commands to achieve what you want (possibly valuable on a loaded system)
you can decompose frequently-used scripts into your own libraries for later use
I choose Perl particularly because it's been designed (perhaps designed is too strong a word for Perl) for these sort of tasks. However you may want to check out Ruby/Python or other suggestions from SO contributers.
For the basic steps look at camh's answer. If you plan to run the script via cron, then implement some simple logging, e.g. by appending start time of each command with exit code to a textfile which you can later analyze for failures of the script.
Expect -- scripting interactive applications
Expect is a tool for automating interactive applications such as telnet, ftp, passwd, fsck, rlogin, tip, etc.... Expect can make easy all sorts of tasks that are prohibitively difficult with anything else. You will find that Expect is an absolutely invaluable tool - using it, you will be able to automate tasks that you've never even thought of before - and you'll be able to do this automation quickly and easily.
http://expect.nist.gov
bonus: Your tax dollars at work!
I would probably do something like this...
project_update.sh
#!/bin/bash
#
# $1 - user#host
# $2 - project directory
[[ -z $1 || -z $2 ]] && { echo "usage: $(basename $0) user#host project_dir"; exit 1; }
declare host=$1 proj_dir=$2
ssh $host "cd $proj_dir;svn update;sudo /etc/init.d/apache2 restart" && echo "Success"
Just to add another tip - you should not give users access to some application in an unknown state. svn up might break during the update, users might see a page that's half-new half-old, etc. If you're deploying the whole application at once, I'd suggest doing svn export instead to a new directory and then either mv current old ; mv new current, or even keeping current as a link to the directory you're using now. Still not perfect and not blocking every possible race condition, but it definitely takes less time than svn up on the live copy.
Problem: Customer X is a Windows user who wants to be able to trigger pre-packaged bash commands by using mnemonic keywords or "tag hints" when she is logged in to her RedHat box via shell.
Example: Customer X logs into host using ssh and wants to do some routine file operations. She wants to be able to type
copy file
and get back a listing of pre-fab fill-in-the-blank bash commands to choose from
cp <#source#> <#dest#> ### simple copy
cp -R <#startdir#> <#destdir#> ### recursive copy
she then wants to be able to select one of these items, fill in the blank(s) and just hit enter to run the command.
Customer X is willing to specify ahead of time what commands she is likely to want to use (in windows-speak) and then hire the developer to translate those into bash commands, and then put them together in a script that allows her to talk windows-speak to bash and get back the list of commands.
NOTE: Customer X doesn't like apropos because it assumes familiarity with terms used in bash, as opposed to windows-speak. For example:
apropos shortcut
doesn't give her anything about creating symlinks (even though that is exactly what she wants) because she doesn't know what windows shortcuts are called in linux. Obviously, windows concepts don't carry over 100% so she will have to learn eventually, but she's a busy person and is asking for this as a way to "ease" her into linux understanding.
Question: What is the best way to get started on something like this? Is there a perl, python, ruby script out there that does something like this already? Is there something in bash that can simulate this kind of feature request?
What you probably want is to override bash's command-not-found handler. Here's the section in /etc/bash.bashrc in a standard Ubuntu install that installs the handler:
...
# if the command-not-found package is installed, use it
if [ -x /usr/lib/command-not-found ]; then
function command_not_found_handle {
# check because c-n-f could've been removed in the meantime
if [ -x /usr/lib/command-not-found ]; then
/usr/bin/python /usr/lib/command-not-found -- $1
return $?
else
return 127
fi
}
fi
...
In effect, if a command is not found, a user specified program is executed with that command as a parameter. In the case of Ubuntu, it's a Python program that checks to see if the command the user typed is a valid application that can be installed, and if it is, informs the user that he/she can install it.
What you probably want to do is compare it to you hashref of commands and usage strings and display the appropriate one if there's a match.