Created
December 14, 2011 15:49
-
-
Save libryder/1477106 to your computer and use it in GitHub Desktop.
Auto SFTP mount script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Copyright (c) Finnbarr P. Murphy 2011. All rights reserved. | |
# | |
# | |
# ARGUMENTS: All are mandatory. | |
# | |
# l - Local folder name. This is the mount point for auto.master | |
# i - Local indirect name. This is the first field of auto.sshfs | |
# The combination of l x i provides infinite flexibility | |
# U - Username for SSH connection. Must be valid on Host. | |
# P - Password for SSH connection (plaintext). Must be valid on Host. | |
# r - Port for SSH connection. Must be valid SSH port on Host. | |
# h - Host for SSH connection. Must exist and be accessible. | |
# u - Local username. Must already exist. | |
# | |
# | |
# EXAMPLES: | |
# | |
# Assuming fpm has a uid of 1000, gid of 1000 | |
# | |
# ./automount -U fpm -P abcdefg -h ultra -r 22 -u fpm -l /sshfs -i fpm | |
# | |
# adds the following line to /etc/auto.master | |
# | |
# /sshfs /etc/auto.sshfs uid=1000,gid=1000,--timeout=30,--ghost | |
# | |
# and (creates if necessary) and adds the following line (broken for clarity) | |
# to /etc/auto.sshfs | |
# | |
# /sshfs -fstype=fuse,port=22,rw,nodev,nonempty,noatime,allow_other, \ | |
# max_read=65536 :sshfs\#fpm@ultra\: | |
# | |
# The following | |
# | |
# ./automount -U finnbarr -P abcbefg -h ultramax -r 22 -u fpm \ | |
# -l /home/fpm/testmount -i finnbarr | |
# | |
# adds the following line to /etc/auto.master (broken for clarity) | |
# | |
# /home/fpm/testmount /etc/auto.home_fpm_testmount \ | |
# uid=1000,gid=1000,--timeout=30,--ghost | |
# | |
# and (creates if necessary) and adds the following line (broken for clarity) | |
# to /etc/auto.home_fpm_testmount | |
# | |
# /home/fpm/testmount -fstype=fuse,port=22,rw,nodev,nonempty,noatime, \ | |
# allow_other,max_read=65536 :sshfs\#finnbarr@ultramax\: | |
# | |
# | |
# NOTES: | |
# | |
# This script was written to use the bash shell. You may have to modify it if you | |
# wish to use another shell. It must be run as root. | |
# | |
# Remote and local users must already exist. This script does not create them. | |
# | |
# Local mount points must already exist. For safety reasons they are not | |
# created on the fly by default. Assign any value to CREATMOUNTDIR to | |
# override. | |
# | |
# If you see "Agent admitted failure to sign using key", do | |
# sudo gconftool-2 --set -t bool /apps/gnome-keyring/daemon-components/ssh false | |
# | |
# Do sudo apt-get update if on a new system before running this script | |
# | |
# Use fusermount -u to force umounts if necessary | |
# | |
# You have to reload your autofs maps after you modify them | |
# | |
# Indirect maps are named /etc/auto.$indirectmap (see below) | |
# There is a separate indrect map per $localmountpoint | |
# | |
# A partial log is provided. See automount.log | |
# | |
# ---- start configurables ---- | |
LOG="./automount.log" | |
PACKAGES=( "fuse-utils" "autofs" "sshfs" "expect") | |
LOCALHOMEDIR="/home" | |
PATH=/usr/sbin:/usr/bin:/sbin:/bin | |
TIMEOUT=60 | |
CREATEMOUNTDIR=y | |
# ----- end configurables ----- | |
function usage { | |
echo "Usage: automount -U remote-username -P remote-password -h remote-host -r port" | |
echo " -u local-username -l local-mount-point -i local-indirect" | |
exit 2 | |
} | |
function check_install { | |
PACKAGE=$1 | |
echo -n "Checking if $PACKAGE package installed. " | |
RESULT=$(/usr/bin/dpkg -s $PACKAGE > /dev/null 2>&1; echo $?) | |
if (( RESULT == 1 )); then | |
echo "Not installed. Installing $PACKAGE package." | |
/usr/bin/apt-get -q -y install $PACKAGE >> $LOG 2>&1 | |
RESULT=$? | |
if (( RESULT != 0 )); then | |
echo "ERROR - failed to install $PACKAGE package ($RESULT). See log" | |
exit 1 | |
fi | |
else | |
echo "Already installed." | |
fi | |
} | |
# --- script starts here | |
echo | |
datestr=$(date) | |
echo "Setup started $datestr" >> $LOG | |
(( $EUID != 0 )) && { | |
echo "ERROR: You must be root to run this script." | |
exit 1 | |
} | |
(( $# == 0 )) && usage | |
username="" | |
password="" | |
host="" | |
port="" | |
localmountpoint="" | |
localindirect="" | |
localuser="" | |
while getopts "U:P:h:r:u:l:i:" OPTION | |
do | |
case $OPTION in | |
U) username="$OPTARG";; | |
P) password="$OPTARG";; | |
h) host="$OPTARG";; | |
r) port="$OPTARG";; | |
l) localmountpoint="$OPTARG";; | |
i) localindirect="$OPTARG";; | |
u) localuser="$OPTARG";; | |
esac | |
done | |
# --- argument checking | |
if [[ -z "$username" ]]; then | |
echo "ERROR - No username entered." | |
exit 1 | |
fi | |
if [[ -z "$password" ]]; then | |
echo "ERROR - No passed entered." | |
exit 1 | |
fi | |
if [[ -z "$port" ]]; then | |
echo "ERROR - No port entered." | |
exit 1 | |
fi | |
if [[ -z "$host" ]]; then | |
echo "ERROR - No host entered." | |
exit 1 | |
fi | |
if [[ -z "$localmountpoint" ]]; then | |
echo "ERROR - No localmountpoint entered." | |
exit 1 | |
fi | |
if [[ -z "$localindirect" ]]; then | |
echo "ERROR - No localindirect entered." | |
exit 1 | |
fi | |
if [[ -z "$localuser" ]]; then | |
echo "ERROR - No localuser entered." | |
exit 1 | |
fi | |
# --- do some sanity checking here | |
echo -n "Checking if $localuser in /etc/passwd. " | |
grep "^$localuser:" /etc/passwd > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 1 )); then | |
echo; echo "ERROR - $localuser not found in /etc/passwd." | |
exit 1 | |
fi | |
echo "Yes" | |
echo -n "Checking connectivity with $host. " | |
ping -q -c 2 $host > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 1 )); then | |
echo; echo "ERROR - could not ping $host." | |
exit 1 | |
fi | |
echo "Reachable." | |
echo -n "Checking local mount point. " | |
if [[ -d $localmountpoint ]]; then | |
echo "Found." | |
else | |
if [[ -z "$CREATEMOUNTDIR" ]]; then | |
echo "Not found." | |
echo "ERROR: Local mount point ($localmountpoint) not found." | |
echo " For safety reasons it must be manually created." | |
exit 1 | |
else | |
mkdir -p $localmountpoint | |
echo "Created." | |
fi | |
fi | |
echo -n "Checking direct and indirect maps. " | |
TMPGREP=$(grep "^$localmountpoint" /etc/auto.master) | |
RESULT=$? | |
if (( RESULT == 0 )); then | |
INDIRECT=$(echo "$TMPGREP" | awk '{print $2}') | |
grep "^$localindirect" $INDIRECT > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 0 )); then | |
echo "Match." | |
echo "ERROR: Combination of $localmountpoint and $localindirect already in use." | |
exit 1 | |
fi | |
fi | |
echo "OK." | |
# --- check for and install any missing packages | |
for PACKAGE in "${PACKAGES[@]}" | |
do | |
check_install $PACKAGE | |
done | |
# --- check fuse module status | |
# --- add to /etc/modprobe | |
# --- add $localuser to /etc/group fuse | |
echo -n "Checking fuse module. " | |
modprobe -l | grep fuse > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 0 )); then | |
echo "Loaded." | |
else | |
modprobe fuse | |
grep "fuse" /etc/modules > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT != 0 )); then | |
echo "fuse" >> /etc/modules | |
fi | |
echo "Added." | |
fi | |
echo -n "Checking if fuse group exists. " | |
grep "^fuse:" /etc/group > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 1 )); then | |
echo; echo "ERROR: fuse is not a member of /etc/group" | |
exit 1 | |
fi | |
echo "Yes." | |
echo -n "Checking if $localuser in fuse group. " | |
grep "^fuse:" /etc/group | grep $localuser > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 1 )); then | |
/usr/sbin/usermod -a -G fuse $localuser | |
RESULT=$? | |
if (( RESULT == 1 )); then | |
echo; echo "ERROR: failed to add $localuser to fuse group" | |
exit 1 | |
fi | |
echo "Added." | |
else | |
echo "Yes." | |
fi | |
# --- the fuse/autofs setup requires root keys to be added to | |
# --- to $username's authorized_keys - so generate keys here if necessary | |
echo -n "Checking for root ssh key files. " | |
SSH_KEYS_FOUND=0 | |
if [[ -d /root/.ssh ]]; then | |
if [[ -s /root/.ssh/id_dsa && -s /root/.ssh/id_dsa.pub ]]; then | |
ssh-keygen -e -f /root/.ssh/id_dsa.pub | grep "1024-bit DSA" > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 0 )); then | |
SSH_KEYS_FOUND=1 | |
fi | |
fi | |
fi | |
if (( SSH_KEYS_FOUND == 1 )); then | |
echo "Found." | |
else | |
echo "Not found." | |
rm -rf /root/.ssh | |
ssh-keygen -q -t dsa -N "" -f /root/.ssh/id_dsa | |
echo "New ssh key files (DSA protocol) generated for root." | |
fi | |
# --- add root's public key to $username@$host authorized keys | |
TMPROOT=expectscript-root.$$ | |
cat <<EOT > $TMPROOT | |
#!/usr/bin/expect | |
if {[llength \$argv] != 4} { | |
puts "usage: \$argv0 localuser username password host" | |
exit 1 | |
} | |
log_file -a expectscript-root.log | |
log_user 0 | |
set localuser [lindex \$argv 0] | |
set username [lindex \$argv 1] | |
set password [lindex \$argv 2] | |
set host [lindex \$argv 3] | |
set timeout 60 | |
spawn /usr/bin/ssh-copy-id -i \$localuser/.ssh/id_dsa.pub \$username@\$host | |
expect { | |
"assword: " { | |
send "$password\n" | |
expect { | |
"expecting." { } | |
"denied" { exit 1 } | |
timeout { exit 1 } | |
} | |
} | |
"(yes/no)? " { | |
send "yes\n" | |
expect { | |
"assword: " { | |
send "$password\n" | |
expect { | |
"expecting." { } | |
"denied" { exit 1 } | |
timeout { exit 1 } | |
} | |
} | |
} | |
} | |
} | |
exit 0 | |
EOT | |
echo -n "Copying root's public key to $host. " | |
chmod 755 $TMPROOT | |
sleep 3 | |
./$TMPROOT /root $username $password $host | |
RESULT=$? | |
cat $TMPROOT >> $LOG | |
rm -f $TMPROOT | |
cat expectscript-root.log >> $LOG | |
if (( RESULT == 0 )); then | |
echo "Succeeded." | |
rm -f expectscript-root.log | |
else | |
echo "Failed." | |
echo "ERROR: Check expectscript-root.log." | |
exit 1 | |
fi | |
# --- check for $localuser public and private ssh keys | |
# --- we need to be $localuser here when using ssh-* utilities | |
echo -n "Checking for $localuser ssh key files. " | |
SSH_KEYS_FOUND=0 | |
if [[ -d $LOCALHOMEDIR/$localuser ]]; then | |
if [[ -s $LOCALHOMEDIR/$localuser/.ssh/id_dsa && -s $LOCALHOMEDIR/$localuser/.ssh/id_dsa.pub ]]; then | |
sudo -u $localuser -- /usr/bin/ssh-keygen -e -f $LOCALHOMEDIR/$localuser/.ssh/id_dsa.pub | grep "1024-bit DSA" > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 0 )); then | |
SSH_KEYS_FOUND=1 | |
fi | |
fi | |
fi | |
if (( SSH_KEYS_FOUND == 1 )); then | |
echo "Found." | |
else | |
echo "Not found." | |
rm -rf $LOCALHOMEDIR/$localuser/.ssh | |
mkdir $LOCALHOMEDIR/$localuser/.ssh | |
chmod 700 $LOCALHOMEDIR/$localuser/.ssh | |
chown -R $localuser:$localuser $LOCALHOMEDIR/$localuser/.ssh | |
sudo -u $localuser -- /usr/bin/ssh-keygen -q -t dsa -N "" -f $LOCALHOMEDIR/$localuser/.ssh/id_dsa | |
echo "New ssh key files generated (DSA protocol)" | |
fi | |
# --- add $localname's public key to $username@$host authorized keys | |
TMPUSER=expectscript-user.$$ | |
cat <<EOT > $TMPUSER | |
#!/usr/bin/expect | |
if {[llength \$argv] != 4} { | |
puts "usage: \$argv0 localuser username password host" | |
exit 1 | |
} | |
log_file -a expectscript-user.log | |
log_user 0 | |
set localuser [lindex \$argv 0] | |
set username [lindex \$argv 1] | |
set password [lindex \$argv 2] | |
set host [lindex \$argv 3] | |
set timeout 60 | |
spawn /usr/bin/ssh-copy-id -i \$localuser/.ssh/id_dsa.pub \$username@\$host | |
expect { | |
"assword: " { | |
send "$password\n" | |
expect { | |
"expecting." { } | |
"denied" { exit 1 } | |
timeout { exit 1 } | |
} | |
} | |
"(yes/no)? " { | |
send "yes\n" | |
expect { | |
"assword: " { | |
send "$password\n" | |
expect { | |
"expecting." { } | |
"denied" { exit 1 } | |
timeout { exit 1 } | |
} | |
} | |
} | |
} | |
} | |
exit 0 | |
EOT | |
echo -n "Copying $localuser's public key to $host. " | |
chmod 755 $TMPUSER | |
sleep 3 | |
./$TMPUSER $LOCALHOMEDIR/$localuser $username $password $host | |
RESULT=$? | |
cat $TMPUSER >> $LOG | |
rm -f $TMPUSER | |
cat expectscript-user.log >> $LOG | |
if (( RESULT == 0 )); then | |
echo "Succeeded." | |
rm -f expectscript-user.log | |
else | |
echo "Failed." | |
echo "ERROR: Check expectscript-user.log." | |
exit 1 | |
fi | |
# --- determine the name of the indirect map associated with $localmountpoint | |
# --- convention is name oa local mount point stripped of leading slashs | |
# --- with other slashes replaced with underbar i.e. /sshfs/fpm --> auto.sshfs_fpm | |
indirectmap="$localmountpoint" | |
indirectmap=$( echo $indirectmap | tr "/" "_") | |
if [[ ${indirectmap:0:1} == "_" ]]; then | |
indirectmap=${indirectmap:1} | |
fi | |
indirectmap="/etc/auto.$indirectmap" | |
echo "indirectmap: $indirectmap" >> $LOG | |
# --- add line to /etc/auto.master | |
grep "$localmountpoint" /etc/auto.master > /dev/null 2>&1 | |
RESULT=$? | |
if (( RESULT == 0 )); then | |
echo "auto.master line already exists" | |
else | |
lastline=$(sed -n '$p' /etc/auto.master) | |
sed -i '$d' /etc/auto.master | |
tuid=$(id -u $localuser) | |
tgid=$(id -g $localuser) | |
echo "$localmountpoint $indirectmap uid=$tuid,gid=$tuid,--timeout=$TIMEOUT,--ghost" >> /etc/auto.master | |
echo "$lastline" >> /etc/auto.master | |
fi | |
# --- add line to $indirectmap | |
echo "$localindirect -fstype=fuse,port=$port,rw,nodev,nonempty,noatime,allow_other,max_read=65536 :sshfs\#$username@$host\:" >> $indirectmap | |
# --- we are done! | |
datestr=$(date) | |
echo "Setup completed $datestr" >> $LOG | |
echo -e "Setup complete. Please (re)start the autofs service.\n" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment