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