Updated to apply cleanly.
[rsync/rsync-patches.git] / openssl-support.diff
1 -----BEGIN PGP SIGNED MESSAGE-----
2 Hash: SHA1
3
4 Hi.
5
6 I've been hacking together a way to use rsync with OpenSSL, and have
7 attached my current patch against a recent CVS tree. The details of
8 this 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
31 All warnings apply; I don't do C programming all that often, so I
32 can't say if I've left any cleanup/compatibility errors in the code.
33
34 Also: <http://rsync.samba.org/lists.html> refers to the (now gone)
35 smart-questions document on tuxedo.org, which should now be catb.org.
36
37 Cheers,
38
39 - -- 
40 Casey Marshall || rsdio@metastatic.org
41 -----BEGIN PGP SIGNATURE-----
42 Version: GnuPG v1.2.1 (GNU/Linux)
43 Comment: Processed by Mailcrypt 3.5.7 <http://mailcrypt.sourceforge.net/>
44
45 iD8DBQE/ih9xgAuWMgRGsWsRAp8RAJ0XyONLiOSDgHHAOBRNO6sZ/P2dRwCeKfu8
46 LEvhhkUglOm3xMyrdJT4u9Q=
47 =aT/N
48 -----END PGP SIGNATURE-----
49
50 --- Makefile.in 2 May 2004 17:04:14 -0000       1.100
51 +++ Makefile.in 8 May 2004 18:40:16 -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   8 May 2004 18:40:16 -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      8 May 2004 18:40:16 -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 29 Apr 2004 19:40:39 -0000      1.90
203 +++ config.h.in 8 May 2004 18:40:16 -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        30 Apr 2004 18:03:33 -0000      1.196
215 +++ configure.in        8 May 2004 18:40:16 -0000
216 @@ -271,6 +271,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      8 May 2004 18:40:16 -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   6 May 2004 21:08:01 -0000       1.148
316 +++ options.c   8 May 2004 18:40:17 -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 @@ -294,6 +306,13 @@ void usage(enum logcode F)
372    rprintf(F," -4  --ipv4                  prefer IPv4\n");
373    rprintf(F," -6  --ipv6                  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    rprintf(F," -h, --help                  show this help screen\n");
383  
384    rprintf(F,"\n");
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    {"ipv4",            '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
396    {"ipv6",            '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     8 May 2004 18:40:17 -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     2 May 2004 16:34:33 -0000       1.200
455 +++ rsync.h     8 May 2004 18:40:17 -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       8 May 2004 18:40:17 -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 +}