forked from RsyncProject/rsync
-
Notifications
You must be signed in to change notification settings - Fork 1
/
rsync-ssl
executable file
·198 lines (175 loc) · 5.02 KB
/
rsync-ssl
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
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/env bash
# This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection.
# By default this script takes rsync args and hands them off to the actual
# rsync command with an --rsh option that makes it open an SSL connection to an
# rsync daemon. See the rsync-ssl manpage for usage details and env variables.
# When the first arg is --HELPER, we are being used by rsync as an --rsh helper
# script, and the args are (note the trailing dot):
#
# rsync-ssl --HELPER HOSTNAME rsync --server --daemon .
#
# --HELPER is not a user-facing option, so it is not documented in the manpage.
# The first SSL setup was based on: http://dozzie.jarowit.net/trac/wiki/RsyncSSL
# Note that an stunnel connection requires at least version 4.x of stunnel.
function rsync_ssl_run {
case "$*" in
*rsync://*) ;;
*::*) ;;
*)
echo "You must use rsync-ssl with a daemon-style hostname." 1>&2
exit 1
;;
esac
exec rsync --rsh="$0 --HELPER" "${@}"
}
function rsync_ssl_helper {
if [[ -z "$RSYNC_SSL_TYPE" ]]; then
found=`path_search openssl stunnel4 stunnel` || exit 1
if [[ "$found" == */openssl ]]; then
RSYNC_SSL_TYPE=openssl
RSYNC_SSL_OPENSSL="$found"
elif [[ "$found" == */gnutls-cli ]]; then
RSYNC_SSL_TYPE=gnutls
RSYNC_SSL_GNUTLS="$found"
else
RSYNC_SSL_TYPE=stunnel
RSYNC_SSL_STUNNEL="$found"
fi
fi
case "$RSYNC_SSL_TYPE" in
openssl)
if [[ -z "$RSYNC_SSL_OPENSSL" ]]; then
RSYNC_SSL_OPENSSL=`path_search openssl` || exit 1
fi
optsep=' '
;;
gnutls)
if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then
RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1
fi
optsep=' '
;;
stunnel)
if [[ -z "$RSYNC_SSL_STUNNEL" ]]; then
RSYNC_SSL_STUNNEL=`path_search stunnel4 stunnel` || exit 1
fi
optsep=' = '
;;
*)
echo "The RSYNC_SSL_TYPE specifies an unknown type: $RSYNC_SSL_TYPE" 1>&2
exit 1
;;
esac
if [[ -z "$RSYNC_SSL_CERT" ]]; then
certopt=""
gnutls_cert_opt=""
else
certopt="-cert$optsep$RSYNC_SSL_CERT"
gnutls_cert_opt="--x509certfile=$RSYNC_SSL_CERT"
fi
if [[ -z "$RSYNC_SSL_KEY" ]]; then
keyopt=""
gnutls_key_opt=""
else
keyopt="-key$optsep$RSYNC_SSL_KEY"
gnutls_key_opt="--x509keyfile=$RSYNC_SSL_KEY"
fi
if [[ -z ${RSYNC_SSL_CA_CERT+x} ]]; then
# RSYNC_SSL_CA_CERT unset - default CA set AND verify:
# openssl:
caopt="-verify_return_error -verify 4"
# gnutls:
gnutls_opts=""
# stunnel:
# Since there is no way of using the default CA certificate collection,
# we cannot do any verification. Thus, stunnel should really only be
# used if nothing else is available.
cafile=""
verify=""
elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then
# RSYNC_SSL_CA_CERT set but empty -do NO verifications:
# openssl:
caopt="-verify 1"
# gnutls:
gnutls_opts="--insecure"
# stunnel:
cafile=""
verify="verifyChain = no"
else
# RSYNC_SSL_CA_CERT set - use CA AND verify:
# openssl:
caopt="-CAfile $RSYNC_SSL_CA_CERT -verify_return_error -verify 4"
# gnutls:
gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT"
# stunnel:
cafile="CAfile = $RSYNC_SSL_CA_CERT"
verify="verifyChain = yes"
fi
port="${RSYNC_PORT:-0}"
if [[ "$port" == 0 ]]; then
port="${RSYNC_SSL_PORT:-874}"
fi
# If the user specified USER@HOSTNAME::module, then rsync passes us
# the -l USER option too, so we must be prepared to ignore it.
if [[ "$1" == "-l" ]]; then
shift 2
fi
hostname="$1"
shift
if [[ -z "$hostname" || "$1" != rsync || "$2" != --server || "$3" != --daemon ]]; then
echo "Usage: rsync-ssl --HELPER HOSTNAME rsync --server --daemon ." 1>&2
exit 1
fi
if [[ $RSYNC_SSL_TYPE == openssl ]]; then
exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt $keyopt -quiet -verify_quiet -servername $hostname -verify_hostname $hostname -connect $hostname:$port
elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then
exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_key_opt $gnutls_opts $hostname:$port
else
# [email protected] came up with this no-tmpfile calling syntax:
exec $RSYNC_SSL_STUNNEL -fd 10 11<&0 <<EOF 10<&0 0<&11 11<&-
foreground = yes
debug = crit
connect = $hostname:$port
client = yes
TIMEOUTclose = 0
$verify
$certopt
$cafile
EOF
fi
}
function path_search {
IFS_SAVE="$IFS"
IFS=:
for prog in "${@}"; do
for dir in $PATH; do
[[ -z "$dir" ]] && dir=.
if [[ -f "$dir/$prog" && -x "$dir/$prog" ]]; then
echo "$dir/$prog"
IFS="$IFS_SAVE"
return 0
fi
done
done
IFS="$IFS_SAVE"
echo "Failed to find on your path: $*" 1>&2
echo "See the rsync-ssl manpage for configuration assistance." 1>&2
return 1
}
if [[ "$#" == 0 ]]; then
echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2
echo "The SSL_TYPE can be openssl or stunnel"
exit 1
fi
if [[ "$1" = --help || "$1" = -h ]]; then
exec rsync --help
fi
if [[ "$1" == --HELPER ]]; then
shift
rsync_ssl_helper "${@}"
fi
if [[ "$1" == --type=* ]]; then
export RSYNC_SSL_TYPE="${1/--type=/}"
shift
fi
rsync_ssl_run "${@}"