x86-64 AVX2 assemby implemenation of get_checksum1() (#174)
[rsync.git] / rsync-ssl
1 #!/usr/bin/env bash
2
3 # This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection.
4
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
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"
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             ;;
54         gnutls)
55             if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then
56                 RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1
57             fi
58             optsep=' '
59             ;;
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=""
74         gnutls_cert_opt=""
75     else
76         certopt="-cert$optsep$RSYNC_SSL_CERT"
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"
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"
92         # gnutls:
93         gnutls_opts=""
94         # stunnel:
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.
98         cafile=""
99         verify=""
100     elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then
101         # RSYNC_SSL_CA_CERT set but empty -do NO verifications:
102         # openssl:
103         caopt="-verify 1"
104         # gnutls:
105         gnutls_opts="--insecure"
106         # stunnel:
107         cafile=""
108         verify="verifyChain = no"
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"
113         # gnutls:
114         gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT"
115         # stunnel:
116         cafile="CAfile = $RSYNC_SSL_CA_CERT"
117         verify="verifyChain = yes"
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"
132     shift
133
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
140         exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt $keyopt -quiet -verify_quiet -servername $hostname -verify_hostname $hostname -connect $hostname:$port
141     elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then
142         exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_key_opt $gnutls_opts $hostname:$port
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
151 $verify
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
179     echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2
180     echo "The SSL_TYPE can be openssl or stunnel"
181     exit 1
182 fi
183
184 if [[ "$1" = --help || "$1" = -h ]]; then
185     exec rsync --help
186 fi
187
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
197
198 rsync_ssl_run "${@}"