We only need one capability marked with a "*".
[rsync.git] / rsync-ssl
blob8101975ac6ef1e9e683e6658a61e49fbe02c5f52
1 #!/usr/bin/env bash
3 # This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection.
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.
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):
12 # rsync-ssl --HELPER HOSTNAME rsync --server --daemon .
14 # --HELPER is not a user-facing option, so it is not documented in the manpage.
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.
19 function rsync_ssl_run {
20 case "$*" in
21 *rsync://*) ;;
22 *::*) ;;
24 echo "You must use rsync-ssl with a daemon-style hostname." 1>&2
25 exit 1
27 esac
29 exec rsync --rsh="$0 --HELPER" "${@}"
32 function rsync_ssl_helper {
33 if [[ -z "$RSYNC_SSL_TYPE" ]]; then
34 found=`path_search openssl stunnel4 stunnel` || exit 1
35 if [[ "$found" == */openssl ]]; then
36 RSYNC_SSL_TYPE=openssl
37 RSYNC_SSL_OPENSSL="$found"
38 elif [[ "$found" == */gnutls-cli ]]; then
39 RSYNC_SSL_TYPE=gnutls
40 RSYNC_SSL_GNUTLS="$found"
41 else
42 RSYNC_SSL_TYPE=stunnel
43 RSYNC_SSL_STUNNEL="$found"
47 case "$RSYNC_SSL_TYPE" in
48 openssl)
49 if [[ -z "$RSYNC_SSL_OPENSSL" ]]; then
50 RSYNC_SSL_OPENSSL=`path_search openssl` || exit 1
52 optsep=' '
54 gnutls)
55 if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then
56 RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1
58 optsep=' '
60 stunnel)
61 if [[ -z "$RSYNC_SSL_STUNNEL" ]]; then
62 RSYNC_SSL_STUNNEL=`path_search stunnel4 stunnel` || exit 1
64 optsep=' = '
67 echo "The RSYNC_SSL_TYPE specifies an unknown type: $RSYNC_SSL_TYPE" 1>&2
68 exit 1
70 esac
72 if [[ -z "$RSYNC_SSL_CERT" ]]; then
73 certopt=""
74 gnutls_cert_opt=""
75 else
76 certopt="cert$optsep$RSYNC_SSL_CERT"
77 gnutls_cert_opt="--x509keyfile=$RSYNC_SSL_CERT"
80 if [[ -z ${RSYNC_SSL_CA_CERT+x} ]]; then
81 # RSYNC_SSL_CA_CERT unset - default CA set AND verify:
82 # openssl:
83 caopt="-verify_return_error -verify 4"
84 # gnutls:
85 gnutls_opts=""
86 # stunnel:
87 # Since there is no way of using the default CA certificate collection,
88 # we cannot do any verification. Thus, stunnel should really only be
89 # used if nothing else is available.
90 cafile=""
91 verify=""
92 elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then
93 # RSYNC_SSL_CA_CERT set but empty -do NO verifications:
94 # openssl:
95 caopt="-verify 1"
96 # gnutls:
97 gnutls_opts="--insecure"
98 # stunnel:
99 cafile=""
100 verify="verifyChain = no"
101 else
102 # RSYNC_SSL_CA_CERT set - use CA AND verify:
103 # openssl:
104 caopt="-CAfile $RSYNC_SSL_CA_CERT -verify_return_error -verify 4"
105 # gnutls:
106 gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT"
107 # stunnel:
108 cafile="CAfile = $RSYNC_SSL_CA_CERT"
109 verify="verifyChain = yes"
112 port="${RSYNC_PORT:-0}"
113 if [[ "$port" == 0 ]]; then
114 port="${RSYNC_SSL_PORT:-874}"
117 # If the user specified USER@HOSTNAME::module, then rsync passes us
118 # the -l USER option too, so we must be prepared to ignore it.
119 if [[ "$1" == "-l" ]]; then
120 shift 2
123 hostname="$1"
124 shift
126 if [[ -z "$hostname" || "$1" != rsync || "$2" != --server || "$3" != --daemon ]]; then
127 echo "Usage: rsync-ssl --HELPER HOSTNAME rsync --server --daemon ." 1>&2
128 exit 1
131 if [[ $RSYNC_SSL_TYPE == openssl ]]; then
132 exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt -quiet -verify_quiet -servername $hostname -connect $hostname:$port
133 elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then
134 exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_opts $hostname:$port
135 else
136 # devzero@web.de came up with this no-tmpfile calling syntax:
137 exec $RSYNC_SSL_STUNNEL -fd 10 11<&0 <<EOF 10<&0 0<&11 11<&-
138 foreground = yes
139 debug = crit
140 connect = $hostname:$port
141 client = yes
142 TIMEOUTclose = 0
143 $verify
144 $certopt
145 $cafile
150 function path_search {
151 IFS_SAVE="$IFS"
152 IFS=:
153 for prog in "${@}"; do
154 for dir in $PATH; do
155 [[ -z "$dir" ]] && dir=.
156 if [[ -f "$dir/$prog" && -x "$dir/$prog" ]]; then
157 echo "$dir/$prog"
158 IFS="$IFS_SAVE"
159 return 0
161 done
162 done
164 IFS="$IFS_SAVE"
165 echo "Failed to find on your path: $*" 1>&2
166 echo "See the rsync-ssl manpage for configuration assistance." 1>&2
167 return 1
170 if [[ "$#" == 0 ]]; then
171 echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2
172 echo "The SSL_TYPE can be openssl or stunnel"
173 exit 1
176 if [[ "$1" = --help || "$1" = -h ]]; then
177 exec rsync --help
180 if [[ "$1" == --HELPER ]]; then
181 shift
182 rsync_ssl_helper "${@}"
185 if [[ "$1" == --type=* ]]; then
186 export RSYNC_SSL_TYPE="${1/--type=/}"
187 shift
190 rsync_ssl_run "${@}"