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