Index: Makefile.in
===================================================================
RCS file: /cvsroot/rsync/Makefile.in,v
retrieving revision 1.96
diff -u -r1.96 Makefile.in
--- Makefile.in	30 Jul 2003 06:12:25 -0000	1.96
+++ Makefile.in	21 Sep 2003 13:51:46 -0000
@@ -39,7 +39,7 @@
 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
 popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
 	popt/popthelp.o popt/poptparse.o
-OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
+OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@ @SSL_OBJS@
 
 TLS_OBJ = tls.o syscall.o lib/permstring.o
 
Index: cleanup.c
===================================================================
RCS file: /cvsroot/rsync/cleanup.c,v
retrieving revision 1.18
diff -u -r1.18 cleanup.c
--- cleanup.c	21 Mar 2003 23:43:50 -0000	1.18
+++ cleanup.c	21 Sep 2003 13:51:46 -0000
@@ -87,6 +87,9 @@
 	int ocode = code;
 	extern int keep_partial;
 	extern int log_got_error;
+#ifdef HAVE_OPENSSL
+	extern int use_ssl;
+#endif
 	static int inside_cleanup = 0;
 
 	if (inside_cleanup > 10) {
@@ -97,6 +100,12 @@
 
 	signal(SIGUSR1, SIG_IGN);
 	signal(SIGUSR2, SIG_IGN);
+
+#ifdef HAVE_OPENSSL
+	if (use_ssl) {
+		end_tls();
+	}
+#endif
 
 	if (verbose > 3)
 		rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n", 
Index: clientserver.c
===================================================================
RCS file: /cvsroot/rsync/clientserver.c,v
retrieving revision 1.110
diff -u -r1.110 clientserver.c
--- clientserver.c	11 Sep 2003 04:00:19 -0000	1.110
+++ clientserver.c	21 Sep 2003 13:51:47 -0000
@@ -39,6 +39,10 @@
 extern struct exclude_struct **server_exclude_list;
 extern char *exclude_path_prefix;
 
+#ifdef HAVE_OPENSSL
+extern int use_ssl;
+#endif
+
 /**
  * Run a client connected to an rsyncd.  The alternative to this
  * function for remote-shell connections is do_cmd().
@@ -56,6 +60,7 @@
 int start_socket_client(char *host, char *path, int argc, char *argv[])
 {
 	int fd, ret;
+	int f_in, f_out;
 	char *p, *user=NULL;
 	extern char *bind_address;
 	extern int default_af_hint;
@@ -90,7 +95,16 @@
 
 	ret = start_inband_exchange(user, path, fd, fd, argc);
 
-	return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
+	f_in = fd;
+	f_out = fd;
+#ifdef HAVE_OPENSSL
+	if (use_ssl) {
+		f_in = get_tls_rfd();
+		f_out = get_tls_wfd();
+	}
+#endif
+
+	return ret < 0? ret : client_run(f_in, f_out, -1, argc, argv);
 }
 
 int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
@@ -145,6 +159,33 @@
 	if (protocol_version > remote_protocol)
 		protocol_version = remote_protocol;
 
+#ifdef HAVE_OPENSSL
+	if (use_ssl) {
+		io_printf(f_out, "#starttls\n");
+		while (1) {
+			if (!read_line(f_in, line, sizeof(line)-1)) {
+				rprintf(FERROR, "rsync: did not receive reply to #starttls\n");
+				return -1;
+			}
+			if (strncmp(line, "@ERROR", 6) == 0) {
+				rprintf(FERROR, "rsync: ssl connection denied\n");
+				return -1;
+			}
+			if (strcmp(line, "@RSYNCD: starttls") == 0) {
+				break;
+			}
+			rprintf(FINFO, "%s\n", line);
+		}
+		if (start_tls(f_in, f_out)) {
+			rprintf(FERROR, "rsync: error during SSL handshake: %s\n",
+				get_ssl_error());
+			return -1;
+		}
+		f_in = get_tls_rfd();
+		f_out = get_tls_wfd();
+	}
+#endif
+
 	p = strchr(path,'/');
 	if (p) *p = 0;
 	io_printf(f_out, "%s\n", path);
@@ -172,6 +213,9 @@
 			 * server to terminate the listing of modules.
 			 * We don't want to go on and transfer
 			 * anything; just exit. */
+#ifdef HAVE_OPENSSL
+			if (use_ssl) end_tls();
+#endif
 			exit(0);
 		}
 
@@ -179,6 +223,9 @@
 			rprintf(FERROR,"%s\n", line);
 			/* This is always fatal; the server will now
 			 * close the socket. */
+#ifdef HAVE_OPENSSL
+			if (use_ssl) end_tls();
+#endif
 			return RERR_STARTCLIENT;
 		} else {
 			rprintf(FINFO,"%s\n", line);
@@ -499,6 +546,7 @@
 		io_printf(fd,"@RSYNCD: EXIT\n");
 }
 
+
 /* this is called when a connection is established to a client
    and we want to start talking. The setup of the system is done from
    here */
@@ -559,6 +607,20 @@
 			send_listing(f_out);
 			return -1;
 		}
+
+#if HAVE_OPENSSL
+		if (use_ssl && strcmp(line, "#starttls") == 0) {
+			io_printf(f_out, "@RSYNCD: starttls\n");
+			if (start_tls(f_in, f_out)) {
+				rprintf(FLOG, "SSL connection failed: %s\n",
+					get_ssl_error());
+				return -1;
+			}
+			f_in = get_tls_rfd();
+			f_out = get_tls_wfd();
+			continue;
+		}
+#endif
 
 		if (*line == '#') {
 			/* it's some sort of command that I don't understand */
Index: config.h.in
===================================================================
RCS file: /cvsroot/rsync/config.h.in,v
retrieving revision 1.81
diff -u -r1.81 config.h.in
--- config.h.in	30 Jul 2003 06:12:38 -0000	1.81
+++ config.h.in	21 Sep 2003 13:51:48 -0000
@@ -169,6 +169,9 @@
 /* */
 #undef HAVE_OFF64_T
 
+/* true if you want to use SSL. */
+#undef HAVE_OPENSSL
+
 /* Define to 1 if you have the `readlink' function. */
 #undef HAVE_READLINK
 
Index: configure
===================================================================
RCS file: /cvsroot/rsync/configure,v
retrieving revision 1.163
diff -u -r1.163 configure
--- configure	30 Jul 2003 06:12:38 -0000	1.163
+++ configure	21 Sep 2003 13:52:19 -0000
@@ -308,7 +308,7 @@
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS RSYNC_VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA HAVE_REMSH EGREP LIBOBJS ALLOCA OBJ_SAVE OBJ_RESTORE CC_SHOBJ_FLAG BUILD_POPT LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS RSYNC_VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA HAVE_REMSH EGREP SSL_OBJS LIBOBJS ALLOCA OBJ_SAVE OBJ_RESTORE CC_SHOBJ_FLAG BUILD_POPT LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -851,6 +851,7 @@
                           turn on extra debug features
   --disable-largefile     omit support for large files
   --disable-ipv6          don't even try to use IPv6
+  --enable-openssl        compile SSL support with OpenSSL.
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -3456,6 +3457,93 @@
 
 fi
 
+# Check whether --enable-openssl or --disable-openssl was given.
+if test "${enable_openssl+set}" = set; then
+  enableval="$enable_openssl"
+
+fi;
+
+if test "x$enable_openssl" != xno
+then
+	have_ssl=yes
+
+echo "$as_me:$LINENO: checking for SSL_library_init in -lssl" >&5
+echo $ECHO_N "checking for SSL_library_init in -lssl... $ECHO_C" >&6
+if test "${ac_cv_lib_ssl_SSL_library_init+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char SSL_library_init ();
+int
+main ()
+{
+SSL_library_init ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_ssl_SSL_library_init=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ssl_SSL_library_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_library_init" >&5
+echo "${ECHO_T}$ac_cv_lib_ssl_SSL_library_init" >&6
+if test $ac_cv_lib_ssl_SSL_library_init = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSSL 1
+_ACEOF
+
+  LIBS="-lssl $LIBS"
+
+else
+  have_ssl=no
+fi
+
+	if test "x$have_ssl" = xyes
+	then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENSSL 1
+_ACEOF
+
+		SSL_OBJS=ssl.o
+
+	fi
+fi
+
 echo "$as_me:$LINENO: checking whether to call shutdown on all sockets" >&5
 echo $ECHO_N "checking whether to call shutdown on all sockets... $ECHO_C" >&6
 case $host_os in
@@ -10691,6 +10779,7 @@
 s,@INSTALL_DATA@,$INSTALL_DATA,;t t
 s,@HAVE_REMSH@,$HAVE_REMSH,;t t
 s,@EGREP@,$EGREP,;t t
+s,@SSL_OBJS@,$SSL_OBJS,;t t
 s,@LIBOBJS@,$LIBOBJS,;t t
 s,@ALLOCA@,$ALLOCA,;t t
 s,@OBJ_SAVE@,$OBJ_SAVE,;t t
Index: configure.in
===================================================================
RCS file: /cvsroot/rsync/configure.in,v
retrieving revision 1.170
diff -u -r1.170 configure.in
--- configure.in	30 Jul 2003 06:12:29 -0000	1.170
+++ configure.in	21 Sep 2003 13:52:21 -0000
@@ -247,6 +247,21 @@
 	AC_SEARCH_LIBS(getaddrinfo, inet6)
 fi
 
+AC_ARG_ENABLE(openssl,
+              AC_HELP_STRING([--enable-openssl], [compile SSL support with OpenSSL.]))
+
+if test "x$enable_openssl" != xno
+then
+	have_ssl=yes
+	AC_CHECK_LIB(ssl, SSL_library_init, , [have_ssl=no])
+	if test "x$have_ssl" = xyes
+	then
+		AC_DEFINE(HAVE_OPENSSL, 1, [true if you want to use SSL.])
+		SSL_OBJS=ssl.o
+		AC_SUBST(SSL_OBJS)
+	fi
+fi
+
 AC_MSG_CHECKING([whether to call shutdown on all sockets])
 case $host_os in
 	*cygwin* ) AC_MSG_RESULT(yes)
Index: main.c
===================================================================
RCS file: /cvsroot/rsync/main.c,v
retrieving revision 1.172
diff -u -r1.172 main.c
--- main.c	11 Sep 2003 04:53:05 -0000	1.172
+++ main.c	21 Sep 2003 13:52:23 -0000
@@ -698,18 +698,33 @@
 	extern int rsync_port;
 	extern int daemon_over_rsh;
 	extern int read_batch;
+#ifdef HAVE_OPENSSL
+	extern int use_ssl;
+#endif
 	int rc;
+	int url_prefix = 0;
 
 	/* Don't clobber argv[] so that ps(1) can still show the right
 	 * command line. */
 	if ((rc = copy_argv(argv)))
 		return rc;
 
-	/* rsync:// always uses rsync server over direct socket connection */
 	if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
+		url_prefix = strlen(URL_PREFIX);
+	}
+#ifdef HAVE_OPENSSL
+	if (strncasecmp(SSL_URL_PREFIX, argv[0], strlen(SSL_URL_PREFIX)) == 0) {
+		if (!use_ssl) init_tls();
+		use_ssl = 1;
+		url_prefix = strlen(SSL_URL_PREFIX);
+	}
+#endif
+
+	/* rsync:// always uses rsync server over direct socket connection */
+	if (url_prefix) {
 		char *host, *path;
 
-		host = argv[0] + strlen(URL_PREFIX);
+		host = argv[0] + url_prefix;
 		p = strchr(host,'/');
 		if (p) {
 			*p = 0;
@@ -758,12 +773,22 @@
 			argv++;
 		} else {
 			am_sender = 1;
+			if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
+				url_prefix = strlen(URL_PREFIX);
+			}
+#ifdef HAVE_OPENSSL
+			if (strncasecmp(SSL_URL_PREFIX, argv[0], strlen(SSL_URL_PREFIX)) == 0) {
+				if (!use_ssl) init_tls();
+				use_ssl = 1;
+				url_prefix = strlen(SSL_URL_PREFIX);
+			}
+#endif
 
 			/* rsync:// destination uses rsync server over direct socket */
-			if (strncasecmp(URL_PREFIX, argv[argc-1], strlen(URL_PREFIX)) == 0) {
+			if (url_prefix) {
 				char *host, *path;
 
-				host = argv[argc-1] + strlen(URL_PREFIX);
+				host = argv[argc-1] + url_prefix;
 				p = strchr(host,'/');
 				if (p) {
 					*p = 0;
Index: options.c
===================================================================
RCS file: /cvsroot/rsync/options.c,v
retrieving revision 1.116
diff -u -r1.116 options.c
--- options.c	11 Sep 2003 04:53:01 -0000	1.116
+++ options.c	21 Sep 2003 13:52:25 -0000
@@ -134,6 +134,13 @@
  * address, or a hostname. **/
 char *bind_address;
 
+#ifdef HAVE_OPENSSL
+int use_ssl = 0;
+extern char *ssl_cert_path;
+extern char *ssl_key_path;
+extern char *ssl_key_passwd;
+extern char *ssl_ca_path;
+#endif
 
 static void print_rsync_version(enum logcode f)
 {
@@ -141,6 +148,7 @@
 	char const *hardlinks = "no ";
 	char const *links = "no ";
 	char const *ipv6 = "no ";
+	char const *ssl = "no ";
 	STRUCT_STAT *dumstat;
 
 #ifdef HAVE_SOCKETPAIR
@@ -159,6 +167,10 @@
 	ipv6 = "";
 #endif
 
+#ifdef HAVE_OPENSSL
+	ssl = "";
+#endif
+
 	rprintf(f, "%s  version %s  protocol version %d\n",
 		RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
 	rprintf(f,
@@ -172,10 +184,10 @@
 	/* Note that this field may not have type ino_t.  It depends
 	 * on the complicated interaction between largefile feature
 	 * macros. */
-	rprintf(f, "              %sIPv6, %d-bit system inums, %d-bit internal inums\n",
+	rprintf(f, "              %sIPv6, %d-bit system inums, %d-bit internal inums, %sssl\n",
 		ipv6,
 		(int) (sizeof(dumstat->st_ino) * 8),
-		(int) (sizeof(INO64_T) * 8));
+		(int) (sizeof(INO64_T) * 8), ssl);
 #ifdef MAINTAINER_MODE
 	rprintf(f, "              panic action: \"%s\"\n",
 		get_panic_action());
@@ -287,6 +299,13 @@
   rprintf(F," -4                          prefer IPv4\n");
   rprintf(F," -6                          prefer IPv6\n");
 #endif
+#ifdef HAVE_OPENSSL
+  rprintf(F,"     --ssl                   allow socket connections to use SSL\n");
+  rprintf(F,"     --ssl-cert=FILE         path to server's SSL certificate\n");
+  rprintf(F,"     --ssl-key=FILE          path to server's SSL private key\n");
+  rprintf(F,"     --ssl-key-passwd=PASS   password for PEM-encoded private key\n");
+  rprintf(F,"     --ssl-ca-certs=FILE     path to trusted CA certificates\n");
+#endif
 
   rprintf(F,"\n");
 
@@ -297,7 +316,7 @@
 enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
       OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
-      OPT_READ_BATCH, OPT_WRITE_BATCH};
+      OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_USE_SSL};
 
 static struct poptOption long_options[] = {
   /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
@@ -381,6 +400,13 @@
   {0,		      '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
   {0,		      '6', POPT_ARG_VAL,    &default_af_hint, AF_INET6, 0, 0 },
 #endif
+#ifdef HAVE_OPENSSL
+  {"ssl",              0,  POPT_ARG_NONE,   0,               OPT_USE_SSL, 0, 0},
+  {"ssl-cert",         0,  POPT_ARG_STRING, &ssl_cert_path,  OPT_USE_SSL, 0, 0},
+  {"ssl-key",          0,  POPT_ARG_STRING, &ssl_key_path,   OPT_USE_SSL, 0, 0},
+  {"ssl-key-passwd",   0,  POPT_ARG_STRING, &ssl_key_passwd, OPT_USE_SSL, 0, 0},
+  {"ssl-ca-certs",     0,  POPT_ARG_STRING, &ssl_ca_path,    OPT_USE_SSL, 0, 0},
+#endif
   {0,0,0,0, 0, 0, 0}
 };
 
@@ -585,6 +611,12 @@
 			return 0;
 #endif
 
+		case OPT_USE_SSL:
+#ifdef HAVE_OPENSSL
+			use_ssl = 1;
+#endif
+			break;
+
 
 		default:
 			/* FIXME: If --daemon is specified, then errors for later
@@ -644,6 +676,17 @@
 
 	if (do_progress && !verbose)
 		verbose = 1;
+
+#ifdef HAVE_OPENSSL
+	if (use_ssl) {
+		if (init_tls()) {
+			snprintf(err_buf, sizeof(err_buf),
+				 "Openssl error: %s\n",
+				 get_ssl_error());
+			return 0;
+		}
+	}
+#endif
 
 	*argv = poptGetArgs(pc);
 	if (*argv)
Index: rsync.h
===================================================================
RCS file: /cvsroot/rsync/rsync.h,v
retrieving revision 1.155
diff -u -r1.155 rsync.h
--- rsync.h	16 Sep 2003 02:49:59 -0000	1.155
+++ rsync.h	21 Sep 2003 13:52:27 -0000
@@ -31,6 +31,7 @@
 
 #define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
 #define URL_PREFIX "rsync://"
+#define SSL_URL_PREFIX "rsyncs://"
 
 #define BACKUP_SUFFIX "~"
 
@@ -290,6 +291,10 @@
 #else
 /* As long as it gets... */
 #define uint64 unsigned off_t
+#endif
+
+#if HAVE_OPENSSL
+#include "ssl.h"
 #endif
 
 /* Starting from protocol version 26, we always use 64-bit
Index: ssl.c
===================================================================
RCS file: ssl.c
diff -N ssl.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ssl.c	21 Sep 2003 13:52:28 -0000
@@ -0,0 +1,353 @@
+/* -*- c-file-style: "linux" -*-
+ * ssl.c: operations for negotiating SSL rsync connections. 
+ *
+ * Copyright (C) 2003  Casey Marshall <rsdio@metastatic.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "rsync.h"
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <string.h>
+
+#define BUF_SIZE 1024
+
+char *ssl_cert_path = NULL;
+char *ssl_key_path = NULL;
+char *ssl_key_passwd = NULL;
+char *ssl_ca_path = NULL;
+static SSL_CTX *ssl_ctx;
+static SSL *ssl;
+static int tls_read[2] = { -1, -1 };
+static int tls_write[2] = { -1, -1 };
+static int ssl_running;
+static int ssl_pid = -1;
+
+/**
+ * A non-interactive callback to be passed to SSL_CTX_set_default_password_cb,
+ * which merely copies the value of ssl_key_passwd into buf. This is
+ * used for when the private key password is supplied via an option.
+ */
+int default_password_cb(char *buf, int n, UNUSED(int f), UNUSED(void *u))
+{
+	if (ssl_key_passwd == NULL || n < strlen(ssl_key_passwd)) {
+		return 0;
+	}
+	strncpy(buf, ssl_key_passwd, n-1);
+	return strlen(ssl_key_passwd);
+}
+
+/**
+ * If verbose, this method traces the status of the SSL handshake.
+ */
+static void info_callback(SSL *ssl, int cb, int val)
+{
+	extern int verbose;
+	char buf[128];
+	char *cbs;
+
+	switch (cb) {
+	case SSL_CB_LOOP: cbs = "SSL_CB_LOOP"; break;
+	case SSL_CB_EXIT: cbs = "SSL_CB_EXIT"; break;
+	case SSL_CB_READ: cbs = "SSL_CB_READ"; break;
+	case SSL_CB_WRITE: cbs = "SSL_CB_WRITE"; break;
+	case SSL_CB_ALERT: cbs = "SSL_CB_ALERT"; break;
+	case SSL_CB_READ_ALERT: cbs = "SSL_CB_READ_ALERT"; break;
+	case SSL_CB_WRITE_ALERT: cbs = "SSL_CB_WRITE_ALERT"; break;
+	case SSL_CB_ACCEPT_LOOP: cbs = "SSL_CB_ACCEPT_LOOP"; break;
+	case SSL_CB_ACCEPT_EXIT: cbs = "SSL_CB_ACCEPT_EXIT"; break;
+	case SSL_CB_CONNECT_LOOP: cbs = "SSL_CB_CONNECT_LOOP"; break;
+	case SSL_CB_CONNECT_EXIT: cbs = "SSL_CB_CONNECT_EXIT"; break;
+	case SSL_CB_HANDSHAKE_START: cbs = "SSL_CB_HANDSHAKE_START"; break;
+	case SSL_CB_HANDSHAKE_DONE: cbs = "SSL_CB_HANDSHAKE_DONE"; break;
+	default:
+		snprintf(buf, sizeof(buf), "??? (%d)", cb);
+		cbs = buf;
+		break;
+	}
+	if (verbose > 2) {
+		rprintf(FLOG, "SSL: info_callback(%p,%s,%d)\n", ssl, cbs, val);
+		if (cb == SSL_CB_HANDSHAKE_DONE) {
+			SSL_CIPHER_description(SSL_get_current_cipher(ssl),
+					       buf, sizeof(buf));
+			rprintf(FLOG, "SSL: cipher: %s", buf);
+		}
+	}
+}
+
+/**
+ * Initializes the SSL context for TLSv1 connections; returns zero on
+ * success.
+ */
+int init_tls(void)
+{
+	if (ssl_ctx) return 0;
+	SSL_library_init();
+	SSL_load_error_strings();
+	ssl_ctx = SSL_CTX_new(TLSv1_method());
+	if (!ssl_ctx) {
+		return 1;
+	}
+	SSL_CTX_set_info_callback(ssl_ctx, info_callback);
+
+	/* Sets the certificate sent to the other party. */
+	if (ssl_cert_path != NULL) {
+		if (SSL_CTX_use_certificate_file(ssl_ctx, ssl_cert_path,
+						 SSL_FILETYPE_PEM) != 1)
+		{
+			return 1;
+		}
+	}
+	/* Set up the simple non-interactive callback if the password
+	   was supplied on the command line. */
+	if (ssl_key_passwd != NULL) {
+		SSL_CTX_set_default_passwd_cb(ssl_ctx, default_password_cb);
+	}
+	/* Sets the private key that matches the public certificate. */
+	if (ssl_key_path != NULL) {
+		if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_key_path,
+						SSL_FILETYPE_PEM) != 1)
+		{
+			return 1;
+		}
+		if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
+			return 1;
+		}
+	}
+	if (ssl_ca_path != NULL) {
+		if (!SSL_CTX_load_verify_locations(ssl_ctx, ssl_ca_path, NULL)) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Returns the error string for the current SSL error, if any.
+ */
+char *get_ssl_error(void)
+{
+	return ERR_error_string(ERR_get_error(), NULL);
+}
+
+/**
+ * Returns the input file descriptor for the SSL connection.
+ */
+int get_tls_rfd(void)
+{
+	return tls_read[0];
+}
+
+/**
+ * Returns the output file descriptor for the SSL connection.
+ */
+int get_tls_wfd(void)
+{
+	return tls_write[1];
+}
+
+/**
+ * Signal handler that ends the SSL connection.
+ */
+static RETSIGTYPE tls_sigusr1(int UNUSED(val))
+{
+	if (ssl) {
+		SSL_shutdown(ssl);
+		SSL_free(ssl);
+		ssl = NULL;
+	}
+	ssl_running = 0;
+}
+
+/**
+ * Negotiates the TLS connection, creates a socket pair for communicating
+ * with the rsync process, then forks into a new process that will handle
+ * the communication.
+ *
+ * 0 is returned on success.
+ */
+int start_tls(int f_in, int f_out)
+{
+	extern int am_daemon;
+	extern int am_server;
+	int tls_fd;
+	int n = 0, r;
+	unsigned char buf1[BUF_SIZE], buf2[BUF_SIZE];
+	int avail1 = 0, avail2 = 0, write1 = 0, write2 = 0;
+	fd_set rd, wd;
+
+	if (fd_pair(tls_read)) {
+		return 1;
+	}
+	if (fd_pair(tls_write)) {
+		return 1;
+	}
+
+	set_blocking(tls_read[0]);
+	set_blocking(tls_read[1]);
+	set_blocking(tls_write[0]);
+	set_blocking(tls_write[1]);
+	set_blocking(f_in);
+	set_blocking(f_out);
+
+	ssl_pid = do_fork();
+	if (ssl_pid < 0)
+		return -1;
+	if (ssl_pid != 0) {
+		close(tls_write[0]);
+		close(tls_read[1]);
+		return 0;
+	}
+
+	signal(SIGUSR1, tls_sigusr1);
+	ssl = SSL_new(ssl_ctx);
+	if (!ssl) {
+		goto closed;
+	}
+	if (am_daemon || am_server) {
+		SSL_set_accept_state(ssl);
+	} else {
+		SSL_set_connect_state(ssl);
+	}
+	SSL_set_rfd(ssl, f_in);
+	SSL_set_wfd(ssl, f_out);
+
+	tls_fd = SSL_get_fd(ssl);
+	n = tls_write[0];
+	n = MAX(tls_read[1], n);
+	n = MAX(tls_fd, n) + 1;
+
+	ssl_running = 1;
+	while (ssl_running) {
+		FD_ZERO(&rd);
+		FD_ZERO(&wd);
+		FD_SET(tls_write[0], &rd);
+		FD_SET(tls_read[1], &wd);
+		FD_SET(tls_fd, &rd);
+		FD_SET(tls_fd, &wd);
+
+		r = select(n, &rd, &wd, NULL, NULL);
+
+		if (r == -1 && errno == EINTR)
+			continue;
+		if (FD_ISSET(tls_write[0], &rd)) {
+			r = read(tls_write[0], buf1+avail1, BUF_SIZE-avail1);
+			if (r >= 0)
+				avail1 += r;
+			else {
+				rprintf(FERROR, "pipe read error: %s\n",
+					strerror(errno));
+				break;
+			}
+		}
+		if (FD_ISSET(tls_fd, &rd)) {
+			r = SSL_read(ssl, buf2+avail2, BUF_SIZE-avail2);
+			if (r > 0)
+				avail2 += r;
+			else {
+				switch (SSL_get_error(ssl, r)) {
+				case SSL_ERROR_ZERO_RETURN:
+					goto closed;
+				case SSL_ERROR_WANT_READ:
+				case SSL_ERROR_WANT_WRITE:
+					break;
+				case SSL_ERROR_SYSCALL:
+					if (r == 0)
+						rprintf(FERROR, "SSL spurious EOF\n");
+					else
+						rprintf(FERROR, "SSL I/O error: %s\n",
+							strerror(errno));
+					goto closed;
+				case SSL_ERROR_SSL:
+					rprintf(FERROR, "SSL: %s\n",
+						ERR_error_string(ERR_get_error(), NULL));
+					goto closed;
+				default:
+					rprintf(FERROR, "unexpected ssl error %d\n", r);
+					goto closed;
+				}
+			}
+		}
+		if (FD_ISSET(tls_read[1], &wd) && write2 < avail2) {
+			r = write(tls_read[1], buf2+write2, avail2-write2);
+			if (r >= 0)
+				write2 += r;
+			else {
+				rprintf(FERROR, "pipe write error: %s\n",
+					strerror(errno));
+				break;
+			}
+		}
+		if (FD_ISSET(tls_fd, &wd) && write1 < avail1) {
+			r = SSL_write(ssl, buf1+write1, avail1-write1);
+			if (r > 0)
+				write1 += r;
+			else {
+				switch (SSL_get_error(ssl, r)) {
+				case SSL_ERROR_ZERO_RETURN:
+					goto closed;
+				case SSL_ERROR_WANT_READ:
+				case SSL_ERROR_WANT_WRITE:
+					break;
+				case SSL_ERROR_SYSCALL:
+					if (r == 0)
+						rprintf(FERROR, "SSL: spurious EOF\n");
+					else
+						rprintf(FERROR, "SSL: I/O error: %s\n",
+							strerror(errno));
+					goto closed;
+				case SSL_ERROR_SSL:
+					rprintf(FERROR, "SSL: %s\n",
+						ERR_error_string(ERR_get_error(), NULL));
+					goto closed;
+				default:
+					rprintf(FERROR, "unexpected ssl error %d\n", r);
+					goto closed;
+				}
+			}
+		}
+		if (avail1 == write1)
+			avail1 = write1 = 0;
+		if (avail2 == write2)
+			avail2 = write2 = 0;
+	}
+
+	/* XXX I'm pretty sure that there is a lot that I am not considering
+	   here. Bugs? Yes, probably. */
+
+	/* We're finished. */
+	closed:
+	close(tls_read[1]);
+	close(tls_write[0]);
+	exit(0);
+}
+
+/**
+ * Ends the TLS connection.
+ */
+void end_tls(void)
+{
+	if (ssl_pid > 0) {
+		kill(ssl_pid, SIGUSR1);
+	}
+}
Index: ssl.h
===================================================================
RCS file: ssl.h
diff -N ssl.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ssl.h	21 Sep 2003 13:52:28 -0000
@@ -0,0 +1,34 @@
+/* -*- c-file-style: "linux" -*-
+ * ssl.h: header for SSL functions.
+ *
+ * Copyright (C) 2003  Casey Marshall <rsdio@metastatic.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SSL_H__
+#define __SSL_H__
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+int init_tls(void);
+int get_tls_rfd(void);
+int get_tls_wfd(void);
+char *get_ssl_error(void);
+int start_tls(int, int);
+void end_tls(void);
+
+#endif /* __SSL_H__ */
