A potential patch to improve --cvs-exclude.
[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
23 And, if the server allows SSL, it replies with
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);
18ae7b87 75--- orig/clientserver.c 2005-03-31 00:24:21
2fd4a7f7 76+++ clientserver.c 2004-10-08 20:44:59
a7219d20 77@@ -45,6 +45,9 @@ extern int select_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;
a2f30171 87@@ -99,8 +102,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);
91+ if (ret < 0)
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
102- return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
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,
a2f30171 107@@ -161,6 +174,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);
a2f30171 141@@ -189,6 +229,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
a2f30171 152@@ -196,6 +240,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
160 return RERR_STARTCLIENT;
161 } else {
162 rprintf(FINFO,"%s\n", line);
a2f30171 163@@ -549,6 +597,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 */
a2f30171 171@@ -598,6 +647,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;
a2f30171 181@@ -607,6 +659,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);
18ae7b87 202--- orig/configure.in 2005-03-29 11:15:05
13bed3dd 203+++ configure.in 2004-07-03 20:22:28
ea238f1c 204@@ -271,6 +271,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)
18ae7b87 226--- orig/options.c 2005-03-31 00:24:21
def2ace9 227+++ options.c 2005-03-01 01:34:42
18ae7b87 228@@ -156,6 +156,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
6ba1be7d 243@@ -181,6 +189,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
6ba1be7d 251@@ -203,6 +212,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,
6ba1be7d 262@@ -216,10 +229,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());
e621c041 275@@ -350,6 +363,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
WD
280+ rprintf(F," --ssl allow socket connections to use SSL\n");
281+ rprintf(F," --ssl-cert=FILE path to server's SSL certificate\n");
282+ rprintf(F," --ssl-key=FILE path to server's SSL private key\n");
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
ea238f1c 286 rprintf(F," -h, --help show this help screen\n");
ce06af28 287
5388f859 288 rprintf(F,"\nUse \"rsync --daemon --help\" to see the daemon-mode command-line options.\n");
e621c041 289@@ -360,7 +380,7 @@ void usage(enum logcode F)
be73a66e 290 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
6ba1be7d 291 OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
ce06af28 292 OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
58a9031f
WD
293- OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
294+ OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE, OPT_USE_SSL,
ce06af28
WD
295 OPT_REFUSED_BASE = 9000};
296
297 static struct poptOption long_options[] = {
e621c041 298@@ -459,6 +479,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
WD
309 /* All these options switch us into daemon-mode option-parsing. */
310 {"address", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
311 {"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
e621c041 312@@ -863,6 +890,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. */
18ae7b87 325@@ -1111,6 +1144,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) {
18ae7b87 343@@ -1478,11 +1522,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;
e621c041 374--- orig/rsync.h 2005-03-28 20:56:55
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
36bbf3d1 384@@ -411,6 +412,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+}