Updating an old patch from the mailing list.
[rsync/rsync-patches.git] / openssl-support.diff
CommitLineData
8a529471 1After applying this patch, run these commands for a successful build:
ce06af28 2
8a529471
WD
3 autoconf
4 autoheader
5 ./configure
6 make proto
7 make
8
9Casey Marshall writes:
ce06af28
WD
10
11I've been hacking together a way to use rsync with OpenSSL, and have
12attached my current patch against a recent CVS tree. The details of
13this implementation are:
14
15 1. The SSL code is added as a "layer" that is forked into its own
16 process.
17
18 2. An SSL connection is established by the client issuing the
19 command:
20
21 #starttls
22
37d262c5 23 And, if the daemon allows SSL, it replies with
ce06af28
WD
24
25 @RSYNCD: starttls
26
27 At which point both sides begin negotiating the SSL connection.
28 Servers that can't or don't want to use SSL just treat it as a
29 normal unknown command.
30
31 3. The SSL code is meant to be unobtrusive, and when this patch is
32 applied the program may still be built with no SSL code.
33
34 4. There are a number of details not implemented.
35
36All warnings apply; I don't do C programming all that often, so I
37can't say if I've left any cleanup/compatibility errors in the code.
38
ce06af28 39
6ba1be7d 40--- orig/Makefile.in 2004-11-02 16:47:15
2fd4a7f7 41+++ Makefile.in 2004-10-08 20:17:06
ce06af28
WD
42@@ -39,7 +39,7 @@ OBJS3=progress.o pipe.o
43 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
44 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
45 popt/popthelp.o popt/poptparse.o
46-OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
47+OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@ @SSL_OBJS@
48
58a9031f 49 TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o
ce06af28 50
6ba1be7d 51--- orig/cleanup.c 2005-03-05 18:58:38
9c015a83
WD
52+++ cleanup.c 2005-01-10 10:43:22
53@@ -22,6 +22,9 @@
54 #include "rsync.h"
55
8a529471 56 extern int io_error;
a7219d20 57+#if HAVE_OPENSSL
8a529471 58+extern int use_ssl;
ce06af28 59+#endif
9c015a83
WD
60 extern int keep_partial;
61 extern int log_got_error;
62 extern char *partial_dir;
a7219d20 63@@ -97,6 +100,11 @@ void _exit_cleanup(int code, const char
ce06af28
WD
64 signal(SIGUSR1, SIG_IGN);
65 signal(SIGUSR2, SIG_IGN);
78114162 66
a7219d20 67+#if HAVE_OPENSSL
ce06af28
WD
68+ if (use_ssl)
69+ end_tls();
70+#endif
78114162 71+
8a529471
WD
72 if (verbose > 3) {
73 rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
27a7053c 74 code, safe_fname(file), line);
5398d042 75--- orig/clientserver.c 2005-05-19 08:52:42
9d3fe73a 76+++ clientserver.c 2005-04-09 17:39:57
5398d042 77@@ -44,6 +44,9 @@ extern int io_timeout;
ce06af28
WD
78 extern int orig_umask;
79 extern int no_detach;
80 extern int default_af_hint;
a7219d20 81+#if HAVE_OPENSSL
ce06af28
WD
82+extern int use_ssl;
83+#endif
84 extern char *bind_address;
4f9b6a01 85 extern struct filter_list_struct server_filter_list;
ac23c334 86 extern char *config_file;
5398d042 87@@ -98,8 +101,18 @@ int start_socket_client(char *host, char
ce06af28
WD
88 exit_cleanup(RERR_SOCKETIO);
89
90 ret = start_inband_exchange(user, path, fd, fd, argc);
9d3fe73a 91+ if (ret)
ce06af28
WD
92+ return ret;
93+
a7219d20 94+#if HAVE_OPENSSL
ce06af28
WD
95+ if (use_ssl) {
96+ int f_in = get_tls_rfd();
97+ int f_out = get_tls_wfd();
98+ return client_run(f_in, f_out, -1, argc, argv);
99+ }
100+#endif
101
9d3fe73a 102- return ret ? ret : client_run(fd, fd, -1, argc, argv);
ce06af28
WD
103+ return client_run(fd, fd, -1, argc, argv);
104 }
105
9be39c35 106 int start_inband_exchange(char *user, char *path, int f_in, int f_out,
5398d042 107@@ -160,6 +173,33 @@ int start_inband_exchange(char *user, ch
be73a66e
WD
108 if (verbose > 1)
109 print_child_argv(sargs);
ce06af28 110
a7219d20 111+#if HAVE_OPENSSL
ce06af28
WD
112+ if (use_ssl) {
113+ io_printf(f_out, "#starttls\n");
114+ while (1) {
115+ if (!read_line(f_in, line, sizeof(line)-1)) {
116+ rprintf(FERROR, "rsync: did not receive reply to #starttls\n");
117+ return -1;
118+ }
119+ if (strncmp(line, "@ERROR", 6) == 0) {
2fd4a7f7 120+ rprintf(FERROR, "%s\n", line);
ce06af28
WD
121+ return -1;
122+ }
123+ if (strcmp(line, "@RSYNCD: starttls") == 0) {
124+ break;
125+ }
126+ rprintf(FINFO, "%s\n", line);
127+ }
128+ if (start_tls(f_in, f_out)) {
129+ rprintf(FERROR, "rsync: error during SSL handshake: %s\n",
130+ get_ssl_error());
131+ return -1;
132+ }
133+ f_in = get_tls_rfd();
134+ f_out = get_tls_wfd();
135+ }
136+#endif
137+
138 p = strchr(path,'/');
139 if (p) *p = 0;
140 io_printf(f_out, "%s\n", path);
5398d042 141@@ -188,6 +228,10 @@ int start_inband_exchange(char *user, ch
ce06af28
WD
142 * server to terminate the listing of modules.
143 * We don't want to go on and transfer
144 * anything; just exit. */
a7219d20 145+#if HAVE_OPENSSL
ce06af28
WD
146+ if (use_ssl)
147+ end_tls();
148+#endif
149 exit(0);
150 }
151
5398d042 152@@ -195,6 +239,10 @@ int start_inband_exchange(char *user, ch
7628f156 153 rprintf(FERROR, "%s\n", line);
ce06af28
WD
154 /* This is always fatal; the server will now
155 * close the socket. */
a7219d20 156+#if HAVE_OPENSSL
ce06af28
WD
157+ if (use_ssl)
158+ end_tls();
159+#endif
9d3fe73a
WD
160 return -1;
161 }
162
5398d042 163@@ -541,6 +589,7 @@ static void send_listing(int fd)
ce06af28
WD
164 io_printf(fd,"@RSYNCD: EXIT\n");
165 }
166
167+
168 /* this is called when a connection is established to a client
169 and we want to start talking. The setup of the system is done from
170 here */
5398d042 171@@ -590,6 +639,9 @@ int start_daemon(int f_in, int f_out)
2fd4a7f7
WD
172 if (protocol_version > remote_protocol)
173 protocol_version = remote_protocol;
174
175+#if HAVE_OPENSSL
176+retry:
177+#endif
178 line[0] = 0;
179 if (!read_line(f_in, line, sizeof line - 1))
180 return -1;
5398d042 181@@ -599,6 +651,20 @@ int start_daemon(int f_in, int f_out)
5e929029
WD
182 return -1;
183 }
78114162 184
ce06af28 185+#if HAVE_OPENSSL
5e929029
WD
186+ if (use_ssl && strcmp(line, "#starttls") == 0) {
187+ io_printf(f_out, "@RSYNCD: starttls\n");
188+ if (start_tls(f_in, f_out)) {
189+ rprintf(FLOG, "SSL connection failed: %s\n",
190+ get_ssl_error());
191+ return -1;
ce06af28 192+ }
5e929029
WD
193+ f_in = get_tls_rfd();
194+ f_out = get_tls_wfd();
2fd4a7f7 195+ goto retry;
5e929029 196+ }
ce06af28 197+#endif
78114162 198+
5e929029
WD
199 if (*line == '#') {
200 /* it's some sort of command that I don't understand */
201 io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
1f874579 202--- orig/configure.in 2005-05-28 08:24:57
13bed3dd 203+++ configure.in 2004-07-03 20:22:28
1f874579 204@@ -284,6 +284,21 @@ yes
ce06af28
WD
205 AC_SEARCH_LIBS(getaddrinfo, inet6)
206 fi
207
208+AC_ARG_ENABLE(openssl,
209+ AC_HELP_STRING([--enable-openssl], [compile SSL support with OpenSSL.]))
210+
211+if test "x$enable_openssl" != xno
212+then
213+ have_ssl=yes
214+ AC_CHECK_LIB(ssl, SSL_library_init, , [have_ssl=no])
215+ if test "x$have_ssl" = xyes
216+ then
217+ AC_DEFINE(HAVE_OPENSSL, 1, [true if you want to use SSL.])
218+ SSL_OBJS=ssl.o
219+ AC_SUBST(SSL_OBJS)
220+ fi
221+fi
222+
223 AC_MSG_CHECKING([whether to call shutdown on all sockets])
224 case $host_os in
225 *cygwin* ) AC_MSG_RESULT(yes)
5398d042
WD
226--- orig/options.c 2005-05-19 08:52:42
227+++ options.c 2005-05-19 08:58:46
c2f72cff 228@@ -157,6 +157,14 @@ int log_format_has_o_or_i = 0;
ce06af28
WD
229 int always_checksum = 0;
230 int list_only = 0;
231
a7219d20 232+#if HAVE_OPENSSL
ce06af28
WD
233+int use_ssl = 0;
234+char *ssl_cert_path = NULL;
235+char *ssl_key_path = NULL;
236+char *ssl_key_passwd = NULL;
237+char *ssl_ca_path = NULL;
238+#endif
239+
9be39c35
WD
240 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
241 char *batch_name = NULL;
242
c2f72cff 243@@ -182,6 +190,7 @@ static void print_rsync_version(enum log
ce06af28
WD
244 char const *hardlinks = "no ";
245 char const *links = "no ";
246 char const *ipv6 = "no ";
247+ char const *ssl = "no ";
248 STRUCT_STAT *dumstat;
249
3d1facaa 250 #ifdef HAVE_SOCKETPAIR
c2f72cff 251@@ -204,6 +213,10 @@ static void print_rsync_version(enum log
ce06af28
WD
252 ipv6 = "";
253 #endif
254
a7219d20 255+#if HAVE_OPENSSL
ce06af28
WD
256+ ssl = "";
257+#endif
258+
259 rprintf(f, "%s version %s protocol version %d\n",
260 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
261 rprintf(f,
c2f72cff 262@@ -217,10 +230,10 @@ static void print_rsync_version(enum log
ce06af28
WD
263 /* Note that this field may not have type ino_t. It depends
264 * on the complicated interaction between largefile feature
265 * macros. */
f6c3b300
WD
266- rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
267+ rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums, %sssl\n",
268 have_inplace, ipv6,
ce06af28 269 (int) (sizeof dumstat->st_ino * 8),
ba50e96c
WD
270- (int) (sizeof (int64) * 8));
271+ (int) (sizeof (int64) * 8), ssl);
ce06af28
WD
272 #ifdef MAINTAINER_MODE
273 rprintf(f, " panic action: \"%s\"\n",
274 get_panic_action());
896871f8 275@@ -352,6 +365,13 @@ void usage(enum logcode F)
d4e89c6a
WD
276 rprintf(F," -4, --ipv4 prefer IPv4\n");
277 rprintf(F," -6, --ipv6 prefer IPv6\n");
ce06af28 278 #endif
a7219d20 279+#if HAVE_OPENSSL
ce06af28 280+ rprintf(F," --ssl allow socket connections to use SSL\n");
37d262c5
WD
281+ rprintf(F," --ssl-cert=FILE path to daemon's SSL certificate\n");
282+ rprintf(F," --ssl-key=FILE path to daemon's SSL private key\n");
ce06af28
WD
283+ rprintf(F," --ssl-key-passwd=PASS password for PEM-encoded private key\n");
284+ rprintf(F," --ssl-ca-certs=FILE path to trusted CA certificates\n");
285+#endif
896871f8 286 rprintf(F," --version print version number\n");
ea238f1c 287 rprintf(F," -h, --help show this help screen\n");
ce06af28 288
5398d042
WD
289@@ -362,7 +382,7 @@ void usage(enum logcode F)
290
291 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
6ba1be7d 292 OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
5398d042
WD
293- OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
294+ OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_USE_SSL,
295 OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
ce06af28
WD
296 OPT_REFUSED_BASE = 9000};
297
5398d042 298@@ -464,6 +484,13 @@ static struct poptOption long_options[]
ea238f1c
WD
299 {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
300 {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
ce06af28 301 #endif
a7219d20 302+#if HAVE_OPENSSL
5388f859
WD
303+ {"ssl", 0, POPT_ARG_NONE, 0, OPT_USE_SSL, 0, 0},
304+ {"ssl-cert", 0, POPT_ARG_STRING, &ssl_cert_path, OPT_USE_SSL, 0, 0},
305+ {"ssl-key", 0, POPT_ARG_STRING, &ssl_key_path, OPT_USE_SSL, 0, 0},
ce06af28 306+ {"ssl-key-passwd", 0, POPT_ARG_STRING, &ssl_key_passwd, OPT_USE_SSL, 0, 0},
5388f859 307+ {"ssl-ca-certs", 0, POPT_ARG_STRING, &ssl_ca_path, OPT_USE_SSL, 0, 0},
ce06af28 308+#endif
5388f859 309 /* All these options switch us into daemon-mode option-parsing. */
5388f859 310 {"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
2b06a19d 311 {"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
5398d042 312@@ -876,6 +903,12 @@ int parse_arguments(int *argc, const cha
4c1f2ca5
WD
313 basis_dir[basis_dir_cnt++] = (char *)arg;
314 break;
ce06af28
WD
315
316+ case OPT_USE_SSL:
a7219d20 317+#if HAVE_OPENSSL
ce06af28
WD
318+ use_ssl = 1;
319+#endif
320+ break;
321+
322 default:
323 /* A large opt value means that set_refuse_options()
27a7053c 324 * turned this option off. */
5398d042 325@@ -1129,6 +1162,17 @@ int parse_arguments(int *argc, const cha
a7219d20 326 if (delay_updates && !partial_dir)
27a7053c 327 partial_dir = partialdir_for_delayupdate;
78114162 328
a7219d20 329+#if HAVE_OPENSSL
ce06af28
WD
330+ if (use_ssl) {
331+ if (init_tls()) {
332+ snprintf(err_buf, sizeof(err_buf),
333+ "Openssl error: %s\n",
334+ get_ssl_error());
335+ return 0;
336+ }
337+ }
338+#endif
78114162 339+
4c1f2ca5 340 if (inplace) {
3d1facaa 341 #ifdef HAVE_FTRUNCATE
4c1f2ca5 342 if (partial_dir) {
5398d042 343@@ -1498,11 +1542,28 @@ char *check_for_hostspec(char *s, char *
def2ace9
WD
344 {
345 char *p;
346 int not_host;
347+ int url_prefix_len = sizeof URL_PREFIX - 1;
348
349- if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) {
350+ if (!port_ptr)
351+ url_prefix_len = 0;
352+ else if (strncasecmp(URL_PREFIX, s, url_prefix_len) != 0) {
353+#if HAVE_OPENSSL
354+ url_prefix_len = sizeof SSL_URL_PREFIX - 1;
355+ if (strncasecmp(SSL_URL_PREFIX, s, url_prefix_len) != 0)
356+ url_prefix_len = 0;
357+ else {
358+ if (!use_ssl)
359+ init_tls();
360+ use_ssl = 1;
361+ }
362+#else
363+ url_prefix_len = 0;
364+#endif
365+ }
366+ if (url_prefix_len) {
367 char *path;
368 int hostlen;
369- s += strlen(URL_PREFIX);
370+ s += url_prefix_len;
371 if ((p = strchr(s, '/')) != NULL) {
372 hostlen = p - s;
373 path = p + 1;
37d262c5 374--- orig/rsync.h 2005-05-03 17:11:01
2fd4a7f7 375+++ rsync.h 2004-10-08 21:01:33
ce06af28
WD
376@@ -32,6 +32,7 @@
377
378 #define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
379 #define URL_PREFIX "rsync://"
380+#define SSL_URL_PREFIX "rsyncs://"
381
382 #define BACKUP_SUFFIX "~"
383
896871f8 384@@ -410,6 +411,11 @@ enum msgcode {
a7219d20 385 # define SIZEOF_INT64 SIZEOF_OFF_T
78114162
WD
386 #endif
387
ce06af28
WD
388+#if HAVE_OPENSSL
389+#include <openssl/ssl.h>
390+#include <openssl/err.h>
78114162
WD
391+#endif
392+
ce06af28 393 /* Starting from protocol version 26, we always use 64-bit
78114162
WD
394 * ino_t and dev_t internally, even if this platform does not
395 * allow files to have 64-bit inums. That's because the
2fd4a7f7
WD
396--- orig/ssl.c 2004-10-08 19:37:22
397+++ ssl.c 2004-10-08 19:37:22
ce06af28
WD
398@@ -0,0 +1,366 @@
399+/* -*- c-file-style: "linux" -*-
400+ * ssl.c: operations for negotiating SSL rsync connections.
401+ *
402+ * Copyright (C) 2003 Casey Marshall <rsdio@metastatic.org>
403+ *
404+ * This program is free software; you can redistribute it and/or modify
405+ * it under the terms of the GNU General Public License as published by
406+ * the Free Software Foundation; either version 2 of the License, or
407+ * (at your option) any later version.
408+ *
409+ * This program is distributed in the hope that it will be useful,
410+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
411+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
412+ * GNU General Public License for more details.
413+ *
414+ * You should have received a copy of the GNU General Public License
415+ * along with this program; if not, write to the Free Software
416+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
417+ */
418+
419+#include "rsync.h"
420+
a7219d20 421+#if HAVE_SYS_SELECT_H
ce06af28
WD
422+#include <sys/select.h>
423+#else
424+#include <sys/time.h>
425+#include <sys/types.h>
426+#include <unistd.h>
427+#endif
428+#include <string.h>
429+
430+#define BUF_SIZE 1024
431+
432+extern int verbose;
433+extern int am_daemon;
434+extern int am_server;
435+
436+extern char *ssl_cert_path;
437+extern char *ssl_key_path;
438+extern char *ssl_key_passwd;
439+extern char *ssl_ca_path;
440+
441+static SSL_CTX *ssl_ctx;
442+static SSL *ssl;
443+static int tls_read[2] = { -1, -1 };
444+static int tls_write[2] = { -1, -1 };
445+static int ssl_running;
446+static int ssl_pid = -1;
447+
448+/**
449+ * A non-interactive callback to be passed to SSL_CTX_set_default_password_cb,
450+ * which merely copies the value of ssl_key_passwd into buf. This is
451+ * used for when the private key password is supplied via an option.
452+ */
453+static int default_password_cb(char *buf, int n, UNUSED(int f), UNUSED(void *u))
454+{
2fd4a7f7 455+ if (ssl_key_passwd == NULL || n < (int)strlen(ssl_key_passwd))
ce06af28
WD
456+ return 0;
457+ strncpy(buf, ssl_key_passwd, n-1);
458+ return strlen(ssl_key_passwd);
459+}
460+
461+/**
462+ * If verbose, this method traces the status of the SSL handshake.
463+ */
2fd4a7f7 464+static void info_callback(const SSL *ssl, int cb, int val)
ce06af28
WD
465+{
466+ char buf[128];
467+ char *cbs;
468+
469+ switch (cb) {
470+ case SSL_CB_LOOP:
471+ cbs = "SSL_CB_LOOP";
472+ break;
473+ case SSL_CB_EXIT:
474+ cbs = "SSL_CB_EXIT";
475+ break;
476+ case SSL_CB_READ:
477+ cbs = "SSL_CB_READ";
478+ break;
479+ case SSL_CB_WRITE:
480+ cbs = "SSL_CB_WRITE";
481+ break;
482+ case SSL_CB_ALERT:
483+ cbs = "SSL_CB_ALERT";
484+ break;
485+ case SSL_CB_READ_ALERT:
486+ cbs = "SSL_CB_READ_ALERT";
487+ break;
488+ case SSL_CB_WRITE_ALERT:
489+ cbs = "SSL_CB_WRITE_ALERT";
490+ break;
491+ case SSL_CB_ACCEPT_LOOP:
492+ cbs = "SSL_CB_ACCEPT_LOOP";
493+ break;
494+ case SSL_CB_ACCEPT_EXIT:
495+ cbs = "SSL_CB_ACCEPT_EXIT";
496+ break;
497+ case SSL_CB_CONNECT_LOOP:
498+ cbs = "SSL_CB_CONNECT_LOOP";
499+ break;
500+ case SSL_CB_CONNECT_EXIT:
501+ cbs = "SSL_CB_CONNECT_EXIT";
502+ break;
503+ case SSL_CB_HANDSHAKE_START:
504+ cbs = "SSL_CB_HANDSHAKE_START";
505+ break;
506+ case SSL_CB_HANDSHAKE_DONE:
507+ cbs = "SSL_CB_HANDSHAKE_DONE";
508+ break;
509+ default:
510+ snprintf(buf, sizeof buf, "??? (%d)", cb);
511+ cbs = buf;
512+ break;
513+ }
514+ if (verbose > 2) {
515+ rprintf(FLOG, "SSL: info_callback(%p,%s,%d)\n", ssl, cbs, val);
516+ if (cb == SSL_CB_HANDSHAKE_DONE) {
2fd4a7f7 517+ SSL_CIPHER_description(SSL_get_current_cipher((SSL*)ssl),
ce06af28
WD
518+ buf, sizeof buf);
519+ rprintf(FLOG, "SSL: cipher: %s", buf);
520+ }
521+ }
522+}
523+
524+/**
525+ * Initializes the SSL context for TLSv1 connections; returns zero on
526+ * success.
527+ */
528+int init_tls(void)
529+{
530+ if (ssl_ctx)
531+ return 0;
532+ SSL_library_init();
533+ SSL_load_error_strings();
534+ ssl_ctx = SSL_CTX_new(TLSv1_method());
535+ if (!ssl_ctx)
536+ return 1;
537+ SSL_CTX_set_info_callback(ssl_ctx, info_callback);
538+
539+ /* Sets the certificate sent to the other party. */
540+ if (ssl_cert_path != NULL
541+ && SSL_CTX_use_certificate_file(ssl_ctx, ssl_cert_path,
542+ SSL_FILETYPE_PEM) != 1)
543+ return 1;
544+ /* Set up the simple non-interactive callback if the password
545+ * was supplied on the command line. */
546+ if (ssl_key_passwd != NULL)
547+ SSL_CTX_set_default_passwd_cb(ssl_ctx, default_password_cb);
548+ /* Sets the private key that matches the public certificate. */
549+ if (ssl_key_path != NULL) {
550+ if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_key_path,
551+ SSL_FILETYPE_PEM) != 1)
552+ return 1;
553+ if (SSL_CTX_check_private_key(ssl_ctx) != 1)
554+ return 1;
555+ }
556+ if (ssl_ca_path != NULL
557+ && !SSL_CTX_load_verify_locations(ssl_ctx, ssl_ca_path, NULL))
558+ return 1;
559+
560+ return 0;
561+}
562+
563+/**
564+ * Returns the error string for the current SSL error, if any.
565+ */
566+char *get_ssl_error(void)
567+{
568+ return ERR_error_string(ERR_get_error(), NULL);
569+}
570+
571+/**
572+ * Returns the input file descriptor for the SSL connection.
573+ */
574+int get_tls_rfd(void)
575+{
576+ return tls_read[0];
577+}
578+
579+/**
580+ * Returns the output file descriptor for the SSL connection.
581+ */
582+int get_tls_wfd(void)
583+{
584+ return tls_write[1];
585+}
586+
587+/**
588+ * Signal handler that ends the SSL connection.
589+ */
590+static RETSIGTYPE tls_sigusr1(int UNUSED(val))
591+{
592+ if (ssl) {
593+ SSL_shutdown(ssl);
594+ SSL_free(ssl);
595+ ssl = NULL;
596+ }
597+ ssl_running = 0;
598+}
599+
600+/**
601+ * Negotiates the TLS connection, creates a socket pair for communicating
602+ * with the rsync process, then forks into a new process that will handle
603+ * the communication.
604+ *
605+ * 0 is returned on success.
606+ */
607+int start_tls(int f_in, int f_out)
608+{
609+ int tls_fd;
610+ int n = 0, r;
611+ unsigned char buf1[BUF_SIZE], buf2[BUF_SIZE];
612+ int avail1 = 0, avail2 = 0, write1 = 0, write2 = 0;
613+ fd_set rd, wd;
614+
615+ if (fd_pair(tls_read))
616+ return 1;
617+ if (fd_pair(tls_write))
618+ return 1;
619+
620+ set_blocking(tls_read[0]);
621+ set_blocking(tls_read[1]);
622+ set_blocking(tls_write[0]);
623+ set_blocking(tls_write[1]);
624+ set_blocking(f_in);
625+ set_blocking(f_out);
626+
627+ ssl_pid = do_fork();
628+ if (ssl_pid < 0)
629+ return -1;
630+ if (ssl_pid != 0) {
631+ close(tls_write[0]);
632+ close(tls_read[1]);
633+ return 0;
634+ }
635+
636+ signal(SIGUSR1, tls_sigusr1);
637+ ssl = SSL_new(ssl_ctx);
638+ if (!ssl)
639+ goto closed;
640+ if (am_daemon || am_server)
641+ SSL_set_accept_state(ssl);
642+ else
643+ SSL_set_connect_state(ssl);
644+ SSL_set_rfd(ssl, f_in);
645+ SSL_set_wfd(ssl, f_out);
646+
647+ tls_fd = SSL_get_fd(ssl);
648+ n = tls_write[0];
649+ n = MAX(tls_read[1], n);
650+ n = MAX(tls_fd, n) + 1;
651+
652+ ssl_running = 1;
653+ while (ssl_running) {
654+ FD_ZERO(&rd);
655+ FD_ZERO(&wd);
656+ FD_SET(tls_write[0], &rd);
657+ FD_SET(tls_read[1], &wd);
658+ FD_SET(tls_fd, &rd);
659+ FD_SET(tls_fd, &wd);
660+
661+ r = select(n, &rd, &wd, NULL, NULL);
662+
663+ if (r == -1 && errno == EINTR)
664+ continue;
665+ if (FD_ISSET(tls_write[0], &rd)) {
666+ r = read(tls_write[0], buf1+avail1, BUF_SIZE-avail1);
667+ if (r >= 0)
668+ avail1 += r;
669+ else {
670+ rprintf(FERROR, "pipe read error: %s\n",
671+ strerror(errno));
672+ break;
673+ }
674+ }
675+ if (FD_ISSET(tls_fd, &rd)) {
676+ r = SSL_read(ssl, buf2+avail2, BUF_SIZE-avail2);
677+ if (r > 0)
678+ avail2 += r;
679+ else {
680+ switch (SSL_get_error(ssl, r)) {
681+ case SSL_ERROR_ZERO_RETURN:
682+ goto closed;
683+ case SSL_ERROR_WANT_READ:
684+ case SSL_ERROR_WANT_WRITE:
685+ break;
686+ case SSL_ERROR_SYSCALL:
687+ if (r == 0)
688+ rprintf(FERROR, "SSL spurious EOF\n");
689+ else
690+ rprintf(FERROR, "SSL I/O error: %s\n",
691+ strerror(errno));
692+ goto closed;
693+ case SSL_ERROR_SSL:
694+ rprintf(FERROR, "SSL: %s\n",
695+ ERR_error_string(ERR_get_error(), NULL));
696+ goto closed;
697+ default:
698+ rprintf(FERROR, "unexpected ssl error %d\n", r);
699+ goto closed;
700+ }
701+ }
702+ }
703+ if (FD_ISSET(tls_read[1], &wd) && write2 < avail2) {
704+ r = write(tls_read[1], buf2+write2, avail2-write2);
705+ if (r >= 0)
706+ write2 += r;
707+ else {
708+ rprintf(FERROR, "pipe write error: %s\n",
709+ strerror(errno));
710+ break;
711+ }
712+ }
713+ if (FD_ISSET(tls_fd, &wd) && write1 < avail1) {
714+ r = SSL_write(ssl, buf1+write1, avail1-write1);
715+ if (r > 0)
716+ write1 += r;
717+ else {
718+ switch (SSL_get_error(ssl, r)) {
719+ case SSL_ERROR_ZERO_RETURN:
720+ goto closed;
721+ case SSL_ERROR_WANT_READ:
722+ case SSL_ERROR_WANT_WRITE:
723+ break;
724+ case SSL_ERROR_SYSCALL:
725+ if (r == 0)
726+ rprintf(FERROR, "SSL: spurious EOF\n");
727+ else
728+ rprintf(FERROR, "SSL: I/O error: %s\n",
729+ strerror(errno));
730+ goto closed;
731+ case SSL_ERROR_SSL:
732+ rprintf(FERROR, "SSL: %s\n",
733+ ERR_error_string(ERR_get_error(), NULL));
734+ goto closed;
735+ default:
736+ rprintf(FERROR, "unexpected ssl error %d\n", r);
737+ goto closed;
738+ }
739+ }
740+ }
741+ if (avail1 == write1)
742+ avail1 = write1 = 0;
743+ if (avail2 == write2)
744+ avail2 = write2 = 0;
745+ }
746+
747+ /* XXX I'm pretty sure that there is a lot that I am not considering
748+ here. Bugs? Yes, probably. */
749+
750+ /* We're finished. */
751+ closed:
752+ close(tls_read[1]);
753+ close(tls_write[0]);
754+ exit(0);
755+}
756+
757+/**
758+ * Ends the TLS connection.
759+ */
760+void end_tls(void)
761+{
762+ if (ssl_pid > 0)
763+ kill(ssl_pid, SIGUSR1);
764+}