ssh authorized_keys command= script example
Posted 06-24-2015 at 11:48 PM by catkin
I found little prior art on the 'net regards ssh authorized_keys command= scripts so it may be useful to share the solution we use with our backup scripts.
The remote computer backslash-escapes command words using bash's printf %q. The received command is available to the command= script in envar SSH_ORIGINAL_COMMAND.
The command= script has three jobs:
Acknowledgements to blog entry "OpenSSH: Going flexible with forced commands (http://binblog.info/2008/10/20/opens...rced-commands/). I did not comment there because I do not have the required WordPress, Twitter or Facebook account.
The remote computer backslash-escapes command words using bash's printf %q. The received command is available to the command= script in envar SSH_ORIGINAL_COMMAND.
The command= script has three jobs:
- Validate the command against a series of custom regexes
- Convert the SSH_ORIGINAL_COMMAND string to individual words
- Run the words as a command
Code:
#! /bin/bash # Copyright (C) 2015 Charles Atkinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Purpose: validates an ssh command and, if it passes, execs it. # Usage: # * Intended to be named in .ssh/authorized_keys after a command= # * Suitable when the ssh commands are generated by bung's rsync-bu.sh # Shell configuration shopt -s extglob # Command regexes readonly df_regex='^df ' readonly rm_tmp_script_regex='^rm rsync_bu\.sh\.......$' readonly rsync_server_regex='^rsync --server ' readonly run_tmp_script_regex='^/bin/bash rsync_bu\.sh\.......$' readonly scp_regex='^scp -t \.$' readonly stat_regex='^stat --format=%F ' # Parsing regexes readonly backslash_regex='^\\' readonly word_end_regex='^([[:space:]]|$)' if [[ $SSH_ORIGINAL_COMMAND =~ $df_regex \ || $SSH_ORIGINAL_COMMAND =~ $rm_tmp_script_regex \ || $SSH_ORIGINAL_COMMAND =~ $rsync_server_regex \ || $SSH_ORIGINAL_COMMAND =~ $run_tmp_script_regex \ || $SSH_ORIGINAL_COMMAND =~ $scp_regex \ || $SSH_ORIGINAL_COMMAND =~ $stat_regex \ ]]; then # Reconstitute command into words, processing any backslash escapes unset cmd str=$SSH_ORIGINAL_COMMAND word= while [[ "$str" != '' ]] # For each word do str=${str##*([[:space:]])} # Discard any leading spaces and tabs while true # For each character do if [[ "$str" =~ $word_end_regex ]]; then cmd+=("$word") word= break elif [[ "$str" =~ $backslash_regex ]]; then next_char="${str:1:1}" if [[ "$next_char" = '' ]]; then echo "${0##*/}: command did not pass validation (trailing backslash in $SSH_ORIGINAL_COMMAND)" >&2 exit 1 else word+=$next_char str=${str:2} fi else word+=${str:0:1} str=${str:1} fi done done exec "${cmd[@]}" else echo "${0##*/}: command did not pass validation ($SSH_ORIGINAL_COMMAND)" >&2 exit 1 fi
Total Comments 0