#! /bin/sh # rcontrol (Bourne shell script) -- execute one of a list of permitted actions on a remote host # This script is designed to have other hard links like "rshutdown". # Note: the list is enforced by the remote host, using a grep-based filter # (in ~root/.authorized_keys) that only allows certain commands to be executed. # Separate passphraseless SSH keys are used for each host. The remote host's # root account is used (therefore "PermitRootLogin without-password" is needed # in sshd_config; it is strongly recommended that this not be set to "yes"). # # Usage: {rshutdown|rreboot|rpoweroff} [ -i ] # or rcontrol -g [ -i ] # or rcontrol -e [ -i ] # Options # -e output the line to be added to .authorized_keys on # -g generate a new key and save it, and also output a line like -e # # Limitations: # Due to the security-related restriction that all permissible commands must be # listed in .authorized_keys, a shutdown delay is not supported. # TO-DO: overcome this limitation using a regular expression (grep is already being used!) # # Installation (Bourne shell): # for cmd in rshutdown rreboot rpoweroff ; do ln rcontrol $cmd ; done # # Installation (C shell): # foreach cmd (rshutdown rreboot rpoweroff) # ln rcontrol $cmd # end # # See Also: # http://www.voipphreak.ca/2007/10/22/shutdown-linux-from-windows-remotely-using-ssh-host-keys/ # is an independently-developed tool using a similar mechanism. # # Version: 1.0.2 self=`basename $0` allowed_options=i:ge # Handle link name # (this sets the command to be run, and/or adds extra options applicable to the # value of $self) case $self in rshutdown) command='shutdown now';; # to single-user mode rreboot) command='shutdown -r now';; rpoweroff) command='shutdown -h now';; rcontrol) allowed_options=ge$allowed_options;; *) echo 'rcontrol: invoked through unknown name' >&2; exit 6;; esac # process options set -- `getopt +$allowed_options "$@"` while [ x$1 != x-- ] ; do case $1 in -e) action=show_auth_entries ;; -g) action=generate ;; -i) keyfile=$2 shift # get rid of the option ;; esac shift # get rid of the option (or its arg if the inner shift already got rid it) done shift # get rid of the "--" # process the remaining (non-option) arguments if [ -z "$1" ] ; then echo "${self}: host name not provided" >&2 exit 7 else host=$1 shift if [ -z $keyfile ] ; then keyfile=$HOME/Hosts/$host/ssh_control_key fi # take one of the three main actions if [ -z "$action" ] ; then if [ -z "$command" ] ; then echo 'rcontrol: named actions not supported' >&2 exit 5 fi if [ -r "$keyfile" ] ; then # when no named action is specified, log into the remote host and perform the command # (the command given in the .authorized_keys file will be executed instead of 'fake_command') echo "$command" | ssh -i $keyfile root@$host fake_command else echo "$self: key file not found ($keyfile)" >&2 exit 10 fi else if [ $action = generate ] ; then # generate per-host passphraseless key ssh-keygen -t dsa -f $keyfile -N '' -C "control key for $host" fi # ASSERT: action is 'show_auth_entries' or something (e.g. 'generate') # that does the same thing during operation ## if expr "$2" : ".*\.pub" ; then ## ID_FILE="$2" ## else ## ID_FILE="$2.pub" ## fi if [ -r "$keyfile.pub" ] ; then # (this happens for all actions) # Now output the necessary record to be placed into .authorized_keys, # containing a forced-command spec (see sshd(8)) and a public key. # The command in this spec is the grep-based filter mentioned above. # # The record consists of the following literal* text: # command="grep -e '^$' -e '^$' | sh" # * text in angle-brackets represents data generated by this script echo -n command='"grep ' for cmd in 'shutdown now' 'shutdown -r now' 'shutdown -h now'; do echo -n "-e '^$cmd$' " done echo -n ' | sh" ' cat $keyfile.pub else echo "$self: public key file not found ($keyfile.pub)" >&2 exit 11 fi fi fi