-
Notifications
You must be signed in to change notification settings - Fork 0
/
sshsudo
executable file
·185 lines (168 loc) · 5.97 KB
/
sshsudo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/bin/bash
#
# sshsudo: 1.0
# Author: [email protected]
#
# The script executes sudo command on one or more remote computers.
# Its arguments are the names to remote sudoers and remote computers.
# The script read the password from the standard input, which should
# be the same for all sudoer accounts. No password is explicitly shown
# in the terminal or logged to files.
# If the command is a local shell script, use '-r' to copy it to
# the remote computers to execute. A temporary script file will be
# automatically created for this purpose.
#
#
# TO DO: It can not execute a command that use the shell special charaters
# on the remote computer, such as & ; ! *, because all arguments
# are wrapped with ''. That means, all special characters have only
# literal meanings. In the case when they are needed, use a script
# instead of a command.
#
# Example:sshsudo [email protected] apt-get check
# sshsudo -r [email protected] myscript.sh
usage()
{
local ProgName=$1;
echo "Usage: $ProgName -r -v [-u user] AccountList Command [Arguments]"
echo " -u Set the default user unless it is given within remote account list"
echo " -r Copy the command(usually the path to local script) to remote computers before execution"
echo " -v Verbose output"
echo " AccountList: [user1@]computer1,[user2@]computer2,[user3@]computer3,..."
echo " or the name to file which contains accounts(user@computer) in separate lines"
echo " Command: The Command/Script to be executed"
echo " Arguments: All arguments to be passed to command."
}
pipewrap()
{
# This function reads in the input from a terminal and output the same.
# The only purpose is to insert PASSWORD for "sudo -S" command.
# After initially insert the password, it simply copy input from terminal
# and send it to ssh command directly
echo $1 # which is password
local lockFile=$2;
while true; do
# The function will exit when output pipe is closed,
if [ ! -e $lockFile ]; then
return 0
fi
# i.e., the ssh
read -t 1 line
if [ $? -eq 0 ]; then
# successfully read
echo $line
fi
done
}
runsudo ()
{
# receive its arguments
local ACCOUNT=$1;
local PASSWORD=$2;
local COMMAND=$3;
local ARGUMENTS=$4;
local DEFAULTUSER=$5;
local COPY=$6;
local VERBOSE=$7;
# Parse account which has the form [email protected]
local REMOTEUSER=${ACCOUNT%%@*}
local REMOTECOMPUTER=${ACCOUNT#*@}
local REMOTESCRIPT=
local REMOTECOMMAND=$COMMAND
local SSHARGS="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
if [ $REMOTEUSER = $REMOTECOMPUTER ]; then
# There is no @, i.e., only computer name is given
REMOTEUSER=$DEFAULTUSER
fi
echo =========================${REMOTEUSER}@$REMOTECOMPUTER: sudo $COMMAND $ARGUMENTS
if [ $COPY -ne 0 ]; then
# Make a script + seconds since 1970-01-01
REMOTESCRIPT=/tmp/`basename $COMMAND``date +%s`
if [ $VERBOSE -ne 0 ]; then
echo $REMOTECOMPUTER: Secure copy \"$COMMAND\" to \"$REMOTESCRIPT\"
fi
# Copy to remote computer. Quote target name on the remote computer for script name
# that contains " "
sshpass -p "$PASSWORD" scp "$SSHARGS" "$COMMAND" "$REMOTEUSER@$REMOTECOMPUTER:'$REMOTESCRIPT'"
REMOTECOMMAND=$REMOTESCRIPT
fi
# Assume we are lucky, result is fine.
local RES=DONE
# Invalidate the sudo timestamp. Simplify the situation. Henceforth sudo always ask for a password
sshpass -p "$PASSWORD" ssh "$SSHARGS" "$REMOTEUSER@$REMOTECOMPUTER" "sudo -K"
# Use lock file to inform pipewrap function to exit.
local lockFile=`mktemp`
eval pipewrap '$PASSWORD' '$lockFile' | (sshpass -p "$PASSWORD" ssh "$SSHARGS" "$REMOTEUSER@$REMOTECOMPUTER" "sudo -S '$REMOTECOMMAND' $ARGUMENTS"; rm "$lockFile")
if [ $? -ne 0 ]; then
RES=FAILED
fi
if [ $COPY -ne 0 ]; then
sshpass -p $PASSWORD ssh "$SSHARGS" "$REMOTEUSER@$REMOTECOMPUTER" rm \'$REMOTESCRIPT\'
if [ $VERBOSE -ne 0 ]; then
echo Remove temporary script \"$REMOTESCRIPT\" at [$REMOTECOMPUTER]
fi
fi
echo ----------------------------------${RES}!!----------------------------------------
}
#=====================================Main Script========================================
#
# Set default values for variables
COMMAND=
ARGUMENTS=
COPY=0
VERBOSE=0
ACCOUNTLIST=
DEFAULTUSER=$USER
# Parse the command line arguments with '-'
while getopts u:hrv o ; do
case "$o" in
[?]) usage $0
exit 1;;
h) usage $0
exit 0;;
u) DEFAULTUSER=$OPTARG;;
v) VERBOSE=1;;
r) COPY=1;;
esac
done
# Read the rest command line arguments
if [ $(($#-$OPTIND+1)) -lt 2 ]; then
echo Error: Account list and command have to be in the arguments
usage $0
exit 4
fi
shift $(($OPTIND-1))
ACCOUNTLIST=$1
shift
COMMAND=$1
shift
for PARAM; do
ARGUMENTS=$ARGUMENTS\'$PARAM\'" "
done
# Check the validity of the script command if remote copy is needed
if [ $COPY -ne 0 ]; then
if [ ! -e "$COMMAND" ]; then
echo \"$COMMAND\" does not exist.
exit 3
fi
if [ ! -x "$COMMAND" ]; then
echo \"$COMMAND\" can not be executed.
exit 3
fi
fi
# Read in the password from the STDIN
read -s -p "Please enter your password:" PASSWORD
echo
# Start running
if [ -e $ACCOUNTLIST ]; then # read accounts from a file
for ACCOUNT in `cat $ACCOUNTLIST`; do
runsudo "$ACCOUNT" "$PASSWORD" "$COMMAND" "$ARGUMENTS" "$DEFAULTUSER" "$COPY" "$VERBOSE";
done
else # ACCOUNTLIST is a comma separated list of user@computer strings.
# Change the internal separation field.
IFS=,
for ACCOUNT in $ACCOUNTLIST; do
runsudo "$ACCOUNT" "$PASSWORD" "$COMMAND" "$ARGUMENTS" "$DEFAULTUSER" "$COPY" "$VERBOSE";
done
fi
#EOF