]>
Commit | Line | Data |
---|---|---|
27e88dec | 1 | #!/usr/bin/env bash |
de78dd68 | 2 | |
6273153c | 3 | # This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection. |
2a87d78f | 4 | |
de78dd68 WD |
5 | # By default this script takes rsync args and hands them off to the actual |
6 | # rsync command with an --rsh option that makes it open an SSL connection to an | |
7 | # rsync daemon. See the rsync-ssl manpage for usage details and env variables. | |
8 | ||
9 | # When the first arg is --HELPER, we are being used by rsync as an --rsh helper | |
10 | # script, and the args are (note the trailing dot): | |
11 | # | |
12 | # rsync-ssl --HELPER HOSTNAME rsync --server --daemon . | |
13 | # | |
14 | # --HELPER is not a user-facing option, so it is not documented in the manpage. | |
15 | ||
16 | # The first SSL setup was based on: http://dozzie.jarowit.net/trac/wiki/RsyncSSL | |
17 | # Note that an stunnel connection requires at least version 4.x of stunnel. | |
18 | ||
19 | function rsync_ssl_run { | |
20 | case "$*" in | |
21 | *rsync://*) ;; | |
22 | *::*) ;; | |
23 | *) | |
24 | echo "You must use rsync-ssl with a daemon-style hostname." 1>&2 | |
25 | exit 1 | |
26 | ;; | |
27 | esac | |
28 | ||
29 | exec rsync --rsh="$0 --HELPER" "${@}" | |
30 | } | |
31 | ||
32 | function rsync_ssl_helper { | |
33 | if [[ -z "$RSYNC_SSL_TYPE" ]]; then | |
628dcceb | 34 | found=`path_search openssl stunnel4 stunnel` || exit 1 |
de78dd68 WD |
35 | if [[ "$found" == */openssl ]]; then |
36 | RSYNC_SSL_TYPE=openssl | |
37 | RSYNC_SSL_OPENSSL="$found" | |
6273153c WD |
38 | elif [[ "$found" == */gnutls-cli ]]; then |
39 | RSYNC_SSL_TYPE=gnutls | |
40 | RSYNC_SSL_GNUTLS="$found" | |
de78dd68 WD |
41 | else |
42 | RSYNC_SSL_TYPE=stunnel | |
43 | RSYNC_SSL_STUNNEL="$found" | |
44 | fi | |
45 | fi | |
46 | ||
47 | case "$RSYNC_SSL_TYPE" in | |
48 | openssl) | |
49 | if [[ -z "$RSYNC_SSL_OPENSSL" ]]; then | |
50 | RSYNC_SSL_OPENSSL=`path_search openssl` || exit 1 | |
51 | fi | |
52 | optsep=' ' | |
53 | ;; | |
6273153c WD |
54 | gnutls) |
55 | if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then | |
56 | RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1 | |
57 | fi | |
58 | optsep=' ' | |
59 | ;; | |
de78dd68 WD |
60 | stunnel) |
61 | if [[ -z "$RSYNC_SSL_STUNNEL" ]]; then | |
62 | RSYNC_SSL_STUNNEL=`path_search stunnel4 stunnel` || exit 1 | |
63 | fi | |
64 | optsep=' = ' | |
65 | ;; | |
66 | *) | |
67 | echo "The RSYNC_SSL_TYPE specifies an unknown type: $RSYNC_SSL_TYPE" 1>&2 | |
68 | exit 1 | |
69 | ;; | |
70 | esac | |
71 | ||
72 | if [[ -z "$RSYNC_SSL_CERT" ]]; then | |
73 | certopt="" | |
6273153c | 74 | gnutls_cert_opt="" |
de78dd68 | 75 | else |
592c6bc3 | 76 | certopt="-cert$optsep$RSYNC_SSL_CERT" |
33379302 F |
77 | gnutls_cert_opt="--x509certfile=$RSYNC_SSL_CERT" |
78 | fi | |
79 | ||
80 | if [[ -z "$RSYNC_SSL_KEY" ]]; then | |
81 | keyopt="" | |
82 | gnutls_key_opt="" | |
83 | else | |
84 | keyopt="-key$optsep$RSYNC_SSL_KEY" | |
85 | gnutls_key_opt="--x509keyfile=$RSYNC_SSL_KEY" | |
de78dd68 WD |
86 | fi |
87 | ||
88 | if [[ -z ${RSYNC_SSL_CA_CERT+x} ]]; then | |
89 | # RSYNC_SSL_CA_CERT unset - default CA set AND verify: | |
90 | # openssl: | |
91 | caopt="-verify_return_error -verify 4" | |
6273153c WD |
92 | # gnutls: |
93 | gnutls_opts="" | |
de78dd68 | 94 | # stunnel: |
628dcceb WD |
95 | # Since there is no way of using the default CA certificate collection, |
96 | # we cannot do any verification. Thus, stunnel should really only be | |
97 | # used if nothing else is available. | |
de78dd68 | 98 | cafile="" |
00ec415a | 99 | verify="" |
de78dd68 WD |
100 | elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then |
101 | # RSYNC_SSL_CA_CERT set but empty -do NO verifications: | |
102 | # openssl: | |
103 | caopt="-verify 1" | |
6273153c WD |
104 | # gnutls: |
105 | gnutls_opts="--insecure" | |
de78dd68 WD |
106 | # stunnel: |
107 | cafile="" | |
00ec415a | 108 | verify="verifyChain = no" |
de78dd68 WD |
109 | else |
110 | # RSYNC_SSL_CA_CERT set - use CA AND verify: | |
111 | # openssl: | |
112 | caopt="-CAfile $RSYNC_SSL_CA_CERT -verify_return_error -verify 4" | |
6273153c WD |
113 | # gnutls: |
114 | gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT" | |
de78dd68 WD |
115 | # stunnel: |
116 | cafile="CAfile = $RSYNC_SSL_CA_CERT" | |
00ec415a | 117 | verify="verifyChain = yes" |
de78dd68 WD |
118 | fi |
119 | ||
120 | port="${RSYNC_PORT:-0}" | |
121 | if [[ "$port" == 0 ]]; then | |
122 | port="${RSYNC_SSL_PORT:-874}" | |
123 | fi | |
124 | ||
125 | # If the user specified USER@HOSTNAME::module, then rsync passes us | |
126 | # the -l USER option too, so we must be prepared to ignore it. | |
127 | if [[ "$1" == "-l" ]]; then | |
128 | shift 2 | |
129 | fi | |
130 | ||
131 | hostname="$1" | |
2a87d78f | 132 | shift |
2a87d78f | 133 | |
de78dd68 WD |
134 | if [[ -z "$hostname" || "$1" != rsync || "$2" != --server || "$3" != --daemon ]]; then |
135 | echo "Usage: rsync-ssl --HELPER HOSTNAME rsync --server --daemon ." 1>&2 | |
136 | exit 1 | |
137 | fi | |
138 | ||
139 | if [[ $RSYNC_SSL_TYPE == openssl ]]; then | |
33379302 | 140 | exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt $keyopt -quiet -verify_quiet -servername $hostname -verify_hostname $hostname -connect $hostname:$port |
6273153c | 141 | elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then |
33379302 | 142 | exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_key_opt $gnutls_opts $hostname:$port |
de78dd68 WD |
143 | else |
144 | # devzero@web.de came up with this no-tmpfile calling syntax: | |
145 | exec $RSYNC_SSL_STUNNEL -fd 10 11<&0 <<EOF 10<&0 0<&11 11<&- | |
146 | foreground = yes | |
147 | debug = crit | |
148 | connect = $hostname:$port | |
149 | client = yes | |
150 | TIMEOUTclose = 0 | |
00ec415a | 151 | $verify |
de78dd68 WD |
152 | $certopt |
153 | $cafile | |
154 | EOF | |
155 | fi | |
156 | } | |
157 | ||
158 | function path_search { | |
159 | IFS_SAVE="$IFS" | |
160 | IFS=: | |
161 | for prog in "${@}"; do | |
162 | for dir in $PATH; do | |
163 | [[ -z "$dir" ]] && dir=. | |
164 | if [[ -f "$dir/$prog" && -x "$dir/$prog" ]]; then | |
165 | echo "$dir/$prog" | |
166 | IFS="$IFS_SAVE" | |
167 | return 0 | |
168 | fi | |
169 | done | |
170 | done | |
171 | ||
172 | IFS="$IFS_SAVE" | |
173 | echo "Failed to find on your path: $*" 1>&2 | |
174 | echo "See the rsync-ssl manpage for configuration assistance." 1>&2 | |
175 | return 1 | |
176 | } | |
177 | ||
178 | if [[ "$#" == 0 ]]; then | |
00ec415a | 179 | echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2 |
628dcceb | 180 | echo "The SSL_TYPE can be openssl or stunnel" |
70d4a945 | 181 | exit 1 |
de78dd68 WD |
182 | fi |
183 | ||
184 | if [[ "$1" = --help || "$1" = -h ]]; then | |
185 | exec rsync --help | |
186 | fi | |
2a87d78f | 187 | |
de78dd68 WD |
188 | if [[ "$1" == --HELPER ]]; then |
189 | shift | |
190 | rsync_ssl_helper "${@}" | |
191 | fi | |
192 | ||
193 | if [[ "$1" == --type=* ]]; then | |
194 | export RSYNC_SSL_TYPE="${1/--type=/}" | |
195 | shift | |
196 | fi | |
6e962ac5 | 197 | |
de78dd68 | 198 | rsync_ssl_run "${@}" |