Here's a new version of my rsync-server-over-remote-shell patch: - diffs (-u) against 2.5.0 - syntax for running rsync server over remote shell is rsync [options] -e ssh source [user@]host::module[/dest] rsync [options] -e ssh [user@]host::module[/source] dest If you need different usernames at the rsyncd and ssh levels, you can do rsync [options] -e "ssh -l ssh-user" source rsyncd-user@host::module[/path] - rsync_module() now uses the SSH_CLIENT environment variable to get an IP address. As Martin mentioned, there is the potential for spoofing here, if the client can control what the SSH_CLIENT environment variable contains. (However, if the client can control the environment on the server side, it can do pretty much whatever it wants anyway....) If you're using this in a locked-down scheme with single-use SSH keys, then there's no way for the client to do anything to the environment, and it should be safe. Cheers -- JD Paul jdpaul@interstel.net P.S. Question -- is the enum { } of all the OPT_ variables in options.c necessary any more? It looks like it's not. On Tue, 20 Nov 2001, JD Paul wrote: > Hi -- > > I've made the changes to my code changes and the new diffs (against > 2.4.6 again) are included below. > > Syntax for running rsync server over a remote shell (e.g. ssh) is now: > > rsync [options] -e ssh source [user@]host::module[/dest] > rsync [options] -e ssh [user@]host::module[/source] dest > > Cheers -- > > JD > jdpaul@interstel.net > ------------------------------------------------------------ Index: authenticate.c =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/authenticate.c,v retrieving revision 1.1.1.5 retrieving revision 1.4 diff -u -b -r1.1.1.5 -r1.4 --- authenticate.c 2001/12/03 23:48:45 1.1.1.5 +++ authenticate.c 2001/12/04 00:10:38 1.4 @@ -203,7 +203,7 @@ otherwise return username */ -char *auth_server(int fd, int module, char *addr, char *leader) +char *auth_server(int f_in, int f_out, int module, char *addr, char *leader) { char *users = lp_auth_users(module); char challenge[16]; @@ -222,9 +222,9 @@ base64_encode(challenge, 16, b64_challenge); - io_printf(fd,"%s%s\n", leader, b64_challenge); + io_printf(f_out,"%s%s\n", leader, b64_challenge); - if (!read_line(fd, line, sizeof(line)-1)) { + if (!read_line(f_in, line, sizeof(line)-1)) { return NULL; } Index: clientserver.c =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/clientserver.c,v retrieving revision 1.1.1.5 retrieving revision 1.11 diff -u -b -r1.1.1.5 -r1.11 --- clientserver.c 2001/12/03 23:48:48 1.1.1.5 +++ clientserver.c 2001/12/04 04:51:10 1.11 @@ -35,34 +35,22 @@ */ int start_socket_client(char *host, char *path, int argc, char *argv[]) { - int fd, i; - char *sargs[MAX_ARGS]; - int sargc=0; - char line[MAXPATHLEN]; + int fd; + int ret; char *p, *user=NULL; extern int remote_version; extern int am_sender; extern char *shell_cmd; - extern int kludge_around_eof; extern char *bind_address; if (argc == 0 && !am_sender) { extern int list_only; list_only = 1; } - - /* This is just a friendliness enhancement: if the connection - * is to an rsyncd then there is no point specifying the -e option. - * Note that this is only set if the -e was explicitly specified, - * not if the environment variable just happens to be set. - * See http://lists.samba.org/pipermail/rsync/2000-September/002744.html - */ - if (shell_cmd) { - rprintf(FERROR, "WARNING: --rsh or -e option ignored when " - "connecting to rsync daemon\n"); - /* continue */ - } + /* this is redundant with code in start_inband_exchange(), but + this short-circuits a problem before we open a socket, and + the extra check won't hurt */ if (*path == '/') { rprintf(FERROR,"ERROR: The remote path must start with a module name not a /\n"); return -1; @@ -75,15 +63,46 @@ *p = 0; } - if (!user) user = getenv("USER"); - if (!user) user = getenv("LOGNAME"); - fd = open_socket_out_wrapped (host, rsync_port, bind_address, global_opts.af_hint); if (fd == -1) { exit_cleanup(RERR_SOCKETIO); } + ret = start_inband_exchange(user, path, fd, fd, argc, argv); + + return (ret < 0 ) ? ret : client_run(fd, fd, -1, argc, argv); +} + +int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc, char *argv[]) +{ + int i; + char *sargs[MAX_ARGS]; + int sargc = 0; + char line[MAXPATHLEN]; + char *p; + extern int remote_version; + extern int kludge_around_eof; + extern int am_sender; + extern int daemon_over_rsh; + + if (argc == 0 && !am_sender) { + extern int list_only; + list_only = 1; + } + + if (*path == '/') { + rprintf(FERROR,"ERROR: The remote path must start with a module name\n"); + return -1; + } + + if (!user) user = getenv("USER"); + if (!user) user = getenv("LOGNAME"); + + /* set daemon_over_rsh to false since we need to build the + true set of args passed through the rsh/ssh connection; + this is a no-op for direct-socket-connection mode */ + daemon_over_rsh = 0; server_options(sargs,&sargc); sargs[sargc++] = "."; @@ -93,9 +112,9 @@ sargs[sargc] = NULL; - io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION); + io_printf(f_out,"@RSYNCD: %d\n", PROTOCOL_VERSION); - if (!read_line(fd, line, sizeof(line)-1)) { + if (!read_line(f_in, line, sizeof(line)-1)) { return -1; } @@ -105,7 +124,7 @@ p = strchr(path,'/'); if (p) *p = 0; - io_printf(fd,"%s\n",path); + io_printf(f_out,"%s\n",path); if (p) *p = '/'; /* Old servers may just drop the connection here, @@ -113,12 +132,12 @@ kludge_around_eof = remote_version < 25; while (1) { - if (!read_line(fd, line, sizeof(line)-1)) { + if (!read_line(f_in, line, sizeof(line)-1)) { return -1; } if (strncmp(line,"@RSYNCD: AUTHREQD ",18) == 0) { - auth_client(fd, user, line+18); + auth_client(f_out, user, line+18); continue; } @@ -131,69 +150,97 @@ kludge_around_eof = False; for (i=0;i 17 && !am_sender)) - io_start_multiplex_in(fd); + io_start_multiplex_in(f_in); } - return client_run(fd, fd, -1, argc, argv); -} + return 0; +} -static int rsync_module(int fd, int i) +static int rsync_module(int f_in, int f_out, int i) { int argc=0; char *argv[MAX_ARGS]; char **argp; char line[MAXPATHLEN]; + char addr_buf[128]; uid_t uid = (uid_t)-2; /* canonically "nobody" */ gid_t gid = (gid_t)-2; char *p; - char *addr = client_addr(fd); - char *host = client_name(fd); + char *addr; + char *host; char *name = lp_name(i); int use_chroot = lp_use_chroot(i); int start_glob=0; int ret; char *request=NULL; extern int am_sender; + extern int am_server; + extern int am_daemon; extern int remote_version; extern int am_root; + if (is_a_socket(f_in)) { + addr = client_addr(f_in); + host = client_name(f_in); + } else { + char *ssh_client = getenv("SSH_CLIENT"); + if (ssh_client) { + strlcpy(addr_buf, ssh_client, sizeof(addr_buf)); + /* truncate SSH_CLIENT to just IP address */ + p = strchr(addr_buf, ' '); + if (p) { + *p = '\0'; + } + addr = addr_buf; + host = "remote.shell.connection"; + } else { + addr = "0.0.0.0"; + host = "remote.shell.connection"; + } + } + if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) { rprintf(FERROR,"rsync denied on module %s from %s (%s)\n", - name, client_name(fd), client_addr(fd)); - io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n", - name, client_name(fd), client_addr(fd)); + name, host, addr); + io_printf(f_out,"@ERROR: access denied to %s from %s (%s)\n", + name, host, addr); return -1; } + if (am_daemon && am_server) { + rprintf(FINFO, "rsync allowed access on module %s from %s (%s)\n", + name, host, addr); + } + if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) { if (errno) { rprintf(FERROR,"failed to open lock file %s : %s\n", lp_lock_file(i), strerror(errno)); - io_printf(fd,"@ERROR: failed to open lock file %s : %s\n", + io_printf(f_out,"@ERROR: failed to open lock file %s : %s\n", lp_lock_file(i), strerror(errno)); } else { rprintf(FERROR,"max connections (%d) reached\n", lp_max_connections(i)); - io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i)); + io_printf(f_out,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i)); } return -1; } - auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD "); + auth_user = auth_server(f_in, f_out, i, addr, "@RSYNCD: AUTHREQD "); if (!auth_user) { rprintf(FERROR,"auth failed on module %s from %s (%s)\n", - name, client_name(fd), client_addr(fd)); - io_printf(fd,"@ERROR: auth failed on module %s\n",name); + name, host, addr); + io_printf(f_out,"@ERROR: auth failed on module %s\n",name); return -1; } @@ -206,7 +253,7 @@ if (!name_to_uid(p, &uid)) { if (!isdigit(*p)) { rprintf(FERROR,"Invalid uid %s\n", p); - io_printf(fd,"@ERROR: invalid uid %s\n", p); + io_printf(f_out,"@ERROR: invalid uid\n"); return -1; } uid = atoi(p); @@ -216,7 +263,7 @@ if (!name_to_gid(p, &gid)) { if (!isdigit(*p)) { rprintf(FERROR,"Invalid gid %s\n", p); - io_printf(fd,"@ERROR: invalid gid %s\n", p); + io_printf(f_out,"@ERROR: invalid gid\n"); return -1; } gid = atoi(p); @@ -259,20 +306,20 @@ */ if (chroot(lp_path(i))) { rsyserr(FERROR, errno, "chroot %s failed", lp_path(i)); - io_printf(fd,"@ERROR: chroot failed\n"); + io_printf(f_out,"@ERROR: chroot failed\n"); return -1; } if (!push_dir("/", 0)) { rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i)); - io_printf(fd,"@ERROR: chdir failed\n"); + io_printf(f_out,"@ERROR: chdir failed\n"); return -1; } } else { if (!push_dir(lp_path(i), 0)) { rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i)); - io_printf(fd,"@ERROR: chdir failed\n"); + io_printf(f_out,"@ERROR: chdir failed\n"); return -1; } sanitize_paths = 1; @@ -281,25 +328,25 @@ if (am_root) { if (setgid(gid)) { rsyserr(FERROR, errno, "setgid %d failed", (int) gid); - io_printf(fd,"@ERROR: setgid failed\n"); + io_printf(f_out,"@ERROR: setgid failed\n"); return -1; } if (setuid(uid)) { rsyserr(FERROR, errno, "setuid %d failed", (int) uid); - io_printf(fd,"@ERROR: setuid failed\n"); + io_printf(f_out,"@ERROR: setuid failed\n"); return -1; } am_root = (getuid() == 0); } - io_printf(fd,"@RSYNCD: OK\n"); + io_printf(f_out,"@RSYNCD: OK\n"); argv[argc++] = "rsyncd"; while (1) { - if (!read_line(fd, line, sizeof(line)-1)) { + if (!read_line(f_in, line, sizeof(line)-1)) { return -1; } @@ -367,7 +414,7 @@ if (remote_version < 23) { if (remote_version == 22 || (remote_version > 17 && am_sender)) - io_start_multiplex_out(fd); + io_start_multiplex_out(f_out); } /* For later protocol versions, we don't start multiplexing @@ -388,7 +435,7 @@ io_timeout = lp_timeout(i); } - start_server(fd, fd, argc, argp); + start_server(f_in, f_out, argc, argp); return 0; } @@ -409,26 +456,29 @@ io_printf(fd,"@RSYNCD: EXIT\n"); } -/* this is called when a socket connection is established to a client +/* 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 */ -static int start_daemon(int fd) +int start_daemon(int f_in, int f_out) { char line[200]; char *motd; int i = -1; extern char *config_file; extern int remote_version; + extern int am_server; if (!lp_load(config_file, 0)) { exit_cleanup(RERR_SYNTAX); } - set_socket_options(fd,"SO_KEEPALIVE"); - set_socket_options(fd,lp_socket_options()); - set_nonblocking(fd); + if ( !am_server ) { + set_socket_options(f_in,"SO_KEEPALIVE"); + set_socket_options(f_in,lp_socket_options()); + set_nonblocking(f_in); + } - io_printf(fd,"@RSYNCD: %d\n", PROTOCOL_VERSION); + io_printf(f_out,"@RSYNCD: %d\n", PROTOCOL_VERSION); motd = lp_motd_file(); if (motd && *motd) { @@ -437,50 +487,49 @@ int len = fread(line, 1, sizeof(line)-1, f); if (len > 0) { line[len] = 0; - io_printf(fd,"%s", line); + io_printf(f_out,"%s", line); } } if (f) fclose(f); - io_printf(fd,"\n"); + io_printf(f_out,"\n"); } - if (!read_line(fd, line, sizeof(line)-1)) { + if (!read_line(f_in, line, sizeof(line)-1)) { return -1; } if (sscanf(line,"@RSYNCD: %d", &remote_version) != 1) { - io_printf(fd,"@ERROR: protocol startup error\n"); + io_printf(f_out,"@ERROR: protocol startup error\n"); return -1; } while (i == -1) { line[0] = 0; - if (!read_line(fd, line, sizeof(line)-1)) { + if (!read_line(f_in, line, sizeof(line)-1)) { return -1; } if (!*line || strcmp(line,"#list")==0) { - send_listing(fd); + send_listing(f_out); return -1; } if (*line == '#') { /* it's some sort of command that I don't understand */ - io_printf(fd,"@ERROR: Unknown command '%s'\n", line); + io_printf(f_out,"@ERROR: Unknown command '%s'\n", line); return -1; } i = lp_number(line); if (i == -1) { - io_printf(fd,"@ERROR: Unknown module '%s'\n", line); + io_printf(f_out,"@ERROR: Unknown module '%s'\n", line); return -1; } } - return rsync_module(fd, i); + return rsync_module(f_in, f_out, i); } - int daemon_main(void) { extern char *config_file; @@ -498,7 +547,7 @@ open("/dev/null", O_RDWR); } - return start_daemon(STDIN_FILENO); + return start_daemon(STDIN_FILENO, STDIN_FILENO); } become_daemon(); Index: main.c =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/main.c,v retrieving revision 1.1.1.7 retrieving revision 1.7 diff -u -b -r1.1.1.7 -r1.7 --- main.c 2001/12/03 23:48:56 1.1.1.7 +++ main.c 2001/12/04 00:10:38 1.7 @@ -133,9 +133,11 @@ int i,argc=0; pid_t ret; char *tok,*dir=NULL; + int dash_l_set = 0; extern int local_server; extern char *rsync_path; extern int blocking_io; + extern int daemon_over_rsh; extern int read_batch; if (!read_batch && !local_server) { /* dw -- added read_batch */ @@ -151,15 +153,23 @@ args[argc++] = tok; } + /* check to see if we've already been given '-l user' in + the remote-shell command */ + for (i=0;i<(argc-1);i++) { + if (!strcmp("-l", args[i]) && (args[i+1][0] != '-')) { + dash_l_set = 1; + } + } + #if HAVE_REMSH /* remsh (on HPUX) takes the arguments the other way around */ args[argc++] = machine; - if (user) { + if (user && !(daemon_over_rsh && dash_l_set)) { args[argc++] = "-l"; args[argc++] = user; } #else - if (user) { + if (user && !(daemon_over_rsh && dash_l_set)) { args[argc++] = "-l"; args[argc++] = user; } @@ -176,8 +186,10 @@ args[argc++] = "."; + if (!daemon_over_rsh) { if (path && *path) args[argc++] = path; + } args[argc] = NULL; @@ -617,15 +629,17 @@ extern int am_sender; extern char *shell_cmd; extern int rsync_port; + extern int daemon_over_rsh; extern int whole_file; extern int read_batch; int rc; /* Don't clobber argv[] so that ps(1) can still show the right command line. */ - if ((rc = copy_argv (argv))) + 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) { char *host, *path; @@ -651,7 +665,13 @@ if (p) { if (p[1] == ':') { *p = 0; - return start_socket_client(argv[0], p+2, argc-1, argv+1); + if (!shell_cmd) { + return start_socket_client(argv[0], p+2, + argc-1, argv+1); + } else { + ++p; + daemon_over_rsh = 1; + } } if (argc < 1) { @@ -675,7 +695,13 @@ whole_file = 1; } else if (p[1] == ':') { *p = 0; - return start_socket_client(argv[argc-1], p+2, argc-1, argv); + if (!shell_cmd) { + return start_socket_client(argv[argc-1], p+2, + argc-1, argv); + } else { + ++p; + daemon_over_rsh = 1; + } } if (argc < 2) { @@ -726,8 +752,20 @@ list_only = 1; } - pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out); + pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path, + &f_in,&f_out); + /* if we're running an rsync server on the remote host over a + remote shell command, we need to do the RSYNCD protocol first */ + if (daemon_over_rsh) { + int tmpret; + tmpret = start_inband_exchange(shell_user, shell_path, + f_in, f_out, argc, argv); + if ( tmpret < 0 ) { + return tmpret; + } + } + ret = client_run(f_in, f_out, pid, argc, argv); fflush(stdout); @@ -813,7 +851,7 @@ set_batch_file_ext(batch_ext); } - if (am_daemon) { + if (am_daemon && !am_server) { return daemon_main(); } @@ -835,7 +873,11 @@ if (am_server) { set_nonblocking(STDIN_FILENO); set_nonblocking(STDOUT_FILENO); + if (am_daemon) { + return start_daemon(STDIN_FILENO, STDOUT_FILENO); + } else { start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv); + } } ret = start_client(argc, argv); Index: options.c =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/options.c,v retrieving revision 1.1.1.5 retrieving revision 1.11 diff -u -b -r1.1.1.5 -r1.11 --- options.c 2001/12/03 23:48:57 1.1.1.5 +++ options.c 2001/12/04 05:30:27 1.11 @@ -21,6 +21,7 @@ #include "rsync.h" #include "popt.h" + int make_backups = 0; int whole_file = 0; int copy_links = 0; @@ -53,6 +54,7 @@ int module_id = -1; int am_server = 0; int am_sender = 0; +int daemon_over_rsh = 0; int recurse = 0; int am_daemon=0; int do_stats=0; @@ -535,6 +537,13 @@ int i, x; args[ac++] = "--server"; + + if (daemon_over_rsh) { + args[ac++] = "--daemon"; + *argc = ac; + /* if we're passing --daemon, we're done */ + return; + } if (!am_sender) args[ac++] = "--sender"; Index: proto.h =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/proto.h,v retrieving revision 1.1.1.7 retrieving revision 1.5 diff -u -b -r1.1.1.7 -r1.5 --- proto.h 2001/12/03 23:48:57 1.1.1.7 +++ proto.h 2001/12/04 00:10:38 1.5 @@ -1,7 +1,7 @@ /* This file is automatically generated with "make proto". DO NOT EDIT */ int allow_access(char *addr, char *host, char *allow_list, char *deny_list); -char *auth_server(int fd, int module, char *addr, char *leader); +char *auth_server(int f_in, int f_out, int module, char *addr, char *leader); void auth_client(int fd, char *user, char *challenge); int make_backup(char *fname); void create_batch_file_ext(); @@ -37,6 +37,8 @@ struct map_struct *buf, int fd1, int fd2); void cleanup_set_pid(int pid); int start_socket_client(char *host, char *path, int argc, char *argv[]); +int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc, char *argv[]); +int start_daemon(int f_in, int f_out); int daemon_main(void); void setup_protocol(int f_out,int f_in); int claim_connection(char *fname,int max_connections); @@ -173,7 +175,7 @@ const char *bind_address, int af_hint); int is_a_socket(int fd); -void start_accept_loop(int port, int (*fn)(int )); +void start_accept_loop(int port, int (*fn)(int, int)); void set_socket_options(int fd, char *options); void become_daemon(void); char *client_addr(int fd); Index: rsync.1 =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/rsync.1,v retrieving revision 1.1.1.7 retrieving revision 1.9 diff -u -b -r1.1.1.7 -r1.9 --- rsync.1 2001/12/03 23:48:58 1.1.1.7 +++ rsync.1 2001/12/04 05:02:26 1.9 @@ -47,7 +47,7 @@ .PP .SH "GENERAL" .PP -There are six different ways of using rsync\&. They are: +There are eight different ways of using rsync\&. They are: .PP .IP o for copying local files\&. This is invoked when neither @@ -75,6 +75,20 @@ separator\&. .IP .IP o +for copying from a remote machine using a remote shell +program as the transport, using rsync server on the remote +machine\&. This is invoked when the source path contains a :: +separator and the --rsh=COMMAND (aka "-e COMMAND") option is +also provided\&. +.IP +.IP o +for copying from the local machine to a remote machine +using a remote shell program as the transport, using rsync +server on the remote machine\&. This is invoked when the +destination path contains a :: separator and the +--rsh=COMMMAND option is also provided\&. +.IP +.IP o for listing files on a remote machine\&. This is done the same way as rsync transfers except that you leave off the local destination\&. @@ -139,7 +153,7 @@ using the --delete option\&. .PP You can also use rsync in local-only mode, where both the source and -destination don\&'t have a \&':\&' in the name\&. In this case it behaves like +destination don\'t have a \':\' in the name\&. In this case it behaves like an improved copy command\&. .PP .RS @@ -155,7 +169,7 @@ transport\&. In this case you will connect to a remote rsync server running on TCP port 873\&. .PP -You may establish the connetcion via a web proxy by setting the +You may establish the connection via a web proxy by setting the environment variable RSYNC_PROXY to a hostname:port pair pointing to your web proxy\&. Note that your web proxy must allow proxying to port 873, this must be configured in your proxy servers ruleset\&. @@ -188,17 +202,70 @@ WARNING: On some systems environment variables are visible to all users\&. On those systems using --password-file is recommended\&. .PP +.SH "CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM" +.PP +It is sometimes useful to be able to set up file transfers using rsync +server capabilities on the remote machine, while still using rsh or +ssh for transport\&. This is especially useful when you want to connect +to a remote machine via ssh (for encryption or to get through a +firewall), but you still want to have access to the rsync server +features (see RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM, +below)\&. +.PP +From the user\'s perspective, using rsync in this way is the same as +using it to connect to an rsync server, except that you must +explicitly set the remote shell program on the command line with +--rsh=COMMAND\&. (Setting RSYNC_RSH in the environment will not turn on +this functionality\&.) +.PP +In order to distinguish between the remote-shell user and the rsync +server user, you can use \'-l user\' on your remote-shell command: +.PP +.RS +rsync -av --rsh="ssh -l ssh-user" rsync-user@host::module[/path] local-path +.RE +.PP +The "ssh-user" will be used at the ssh level; the "rsync-user" will be +used to check against the rsyncd\&.conf on the remote host\&. +.PP .SH "RUNNING AN RSYNC SERVER" .PP An rsync server is configured using a config file which by default is called /etc/rsyncd\&.conf\&. Please see the rsyncd\&.conf(5) man page for more information\&. .PP +.SH "RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM" +.PP +See the rsyncd\&.conf(5) man page for full information on the rsync +server configuration file\&. +.PP +Several configuration options will not be available unless the remote +user is root (e\&.g\&. chroot, setuid/setgid, etc\&.)\&. There is no need to +configure inetd or the services map to include the rsync server port +if you run an rsync server only via a remote shell program\&. +.PP +To run an rsync server out of a single-use ssh key, use the +"command=\fICOMMAND\fP" syntax in the remote user\'s +authorized_keys entry, where command would be +.PP +.RS +rsync --server --daemon \&. +.RE +.PP +NOTE: rsync\'s argument parsing expects the trailing "\&.", so make sure +that it\'s there\&. If you want to use a rsyncd\&.conf(5)-style +configuration file other than /etc/rsyncd\&.conf, you can added a +--config-file option to the \fIcommand\fP: +.PP +.RS +rsync --server --daemon --config-file=\fIfile\fP \&. +.RE +.PP .SH "EXAMPLES" .PP Here are some examples of how I use rsync\&. .PP -To backup my wife\&'s home directory, which consists of large MS Word +To backup my wife\'s home directory, which consists of large MS Word files and mail folders, I use a cron job that runs .PP .RS @@ -214,7 +281,7 @@ .RS get: .br -rsync -avuzb --exclude \&'*~\&' samba:samba/ \&. +rsync -avuzb --exclude \'*~\' samba:samba/ \&. .PP put: .br @@ -225,7 +292,7 @@ .PP this allows me to sync with a CVS directory at the other end of the link\&. I then do cvs operations on the remote machine, which saves a -lot of time as the remote cvs protocol isn\&'t very efficient\&. +lot of time as the remote cvs protocol isn\'t very efficient\&. .PP I mirror a directory between my "old" and "new" ftp sites with the command @@ -254,7 +321,7 @@ -b, --backup make backups (default ~ suffix) --backup-dir make backups into this directory --suffix=SUFFIX override backup suffix - -u, --update update only (don\&'t overwrite newer files) + -u, --update update only (don\'t overwrite newer files) -l, --links preserve soft links -L, --copy-links treat soft links like regular files --copy-unsafe-links copy links outside the source tree @@ -268,22 +335,22 @@ -S, --sparse handle sparse files efficiently -n, --dry-run show what would have been transferred -W, --whole-file copy whole files, no incremental checks - -x, --one-file-system don\&'t cross filesystem boundaries + -x, --one-file-system don\'t cross filesystem boundaries -B, --block-size=SIZE checksum blocking size (default 700) -e, --rsh=COMMAND specify rsh replacement --rsync-path=PATH specify path to rsync on the remote machine -C, --cvs-exclude auto ignore files in the same way CVS does --existing only update files that already exist - --delete delete files that don\&'t exist on the sending side + --delete delete files that don\'t exist on the sending side --delete-excluded also delete excluded files on the receiving side --delete-after delete after transferring, not before --ignore-errors delete even if there are IO errors - --max-delete=NUM don\&'t delete more than NUM files + --max-delete=NUM don\'t delete more than NUM files --partial keep partially transferred files --force force deletion of directories even if not empty - --numeric-ids don\&'t map uid/gid values by user/group name + --numeric-ids don\'t map uid/gid values by user/group name --timeout=TIME set IO timeout in seconds - -I, --ignore-times don\&'t exclude files that match length and time + -I, --ignore-times don\'t exclude files that match length and time --size-only only use file size when determining if a file should be transferred --modify-window=NUM Timestamp window (seconds) for file match (default=0) -T --temp-dir=DIR create temporary files in directory DIR @@ -292,8 +359,8 @@ -z, --compress compress file data --exclude=PATTERN exclude files matching PATTERN --exclude-from=FILE exclude patterns listed in FILE - --include=PATTERN don\&'t exclude files matching PATTERN - --include-from=FILE don\&'t exclude patterns listed in FILE + --include=PATTERN don\'t exclude files matching PATTERN + --include-from=FILE don\'t exclude patterns listed in FILE --version print version number --daemon run as a rsync daemon --address bind to the specified address @@ -320,7 +387,7 @@ rsync uses the GNU long options package\&. Many of the command line options have two variants, one short and one long\&. These are shown below, separated by commas\&. Some options only have a long variant\&. -The \&'=\&' for options that take a parameter is optional; whitespace +The \'=\' for options that take a parameter is optional; whitespace can be used instead\&. .PP .IP "\fB-h, --help\fP" @@ -384,7 +451,7 @@ .IP .IP "\fB-r, --recursive\fP" This tells rsync to copy directories -recursively\&. If you don\&'t specify this then rsync won\&'t copy +recursively\&. If you don\'t specify this then rsync won\'t copy directories at all\&. .IP .IP "\fB-R, --relative\fP" @@ -502,7 +569,7 @@ option is not used, the optimization that excludes files that have not been modified cannot be effective; in other words, a missing -t or -a will cause the next transfer to behave as if it used -I, and all files will have -their checksums compared and show up in log messages even if they haven\&'t +their checksums compared and show up in log messages even if they haven\'t changed\&. .IP .IP "\fB-n, --dry-run\fP" @@ -513,8 +580,8 @@ Try to handle sparse files efficiently so they take up less space on the destination\&. .IP -NOTE: Don\&'t use this option when the destination is a Solaris "tmpfs" -filesystem\&. It doesn\&'t seem to handle seeks over null regions +NOTE: Don\'t use this option when the destination is a Solaris "tmpfs" +filesystem\&. It doesn\'t seem to handle seeks over null regions correctly and ends up corrupting the files\&. .IP .IP "\fB-x, --one-file-system\fP" @@ -533,14 +600,14 @@ .IP .IP "\fB--delete\fP" This tells rsync to delete any files on the receiving -side that aren\&'t on the sending side\&. Files that are excluded from +side that aren\'t on the sending side\&. Files that are excluded from transfer are excluded from being deleted unless you use --delete-excluded\&. .IP This option has no effect if directory recursion is not selected\&. .IP This option can be dangerous if used incorrectly! It is a very good idea to run first using the dry run option (-n) to see what files would be -deleted to make sure important files aren\&'t listed\&. +deleted to make sure important files aren\'t listed\&. .IP If the sending side detects any IO errors then the deletion of any files at the destination will be automatically disabled\&. This is to @@ -582,14 +649,29 @@ remote copies of rsync\&. By default, rsync will use rsh, but you may like to instead use ssh because of its high security\&. .IP +If this option is used with \fB[user@]host::module/path\fP, then the +remote shell \fICOMMMAND\fP will be used to run an rsync server on the +remote host, and all data will be transmitted through that remote +shell connection, rather than through a direct socket connection to a +running rsync server on the remote host\&. +.IP You can also choose the remote shell program using the RSYNC_RSH environment variable\&. .IP +In either case, rsync will tokenize the remote-shell command, so you +can use constructions like +.IP +.RS +rsync [options] --rsh="ssh -l user -i identity" source dest +.RE +.IP +to control things at a fine level\&. +.IP See also the --blocking-io option which is affected by this option\&. .IP .IP "\fB--rsync-path=PATH\fP" Use this to specify the path to the copy of -rsync on the remote machine\&. Useful when it\&'s not in your path\&. Note +rsync on the remote machine\&. Useful when it\'s not in your path\&. Note that this is the full path to the binary, not just the directory that the binary is in\&. .IP @@ -608,7 +690,7 @@ This option is similar to the --exclude option, but instead it adds all exclude patterns listed in the file FILE to the exclude list\&. Blank lines in FILE and lines starting with -\&';\&' or \&'#\&' are ignored\&. +\';\' or \'#\' are ignored\&. .IP .IP "\fB--include=PATTERN\fP" This option tells rsync to not exclude the @@ -624,7 +706,7 @@ .IP .IP "\fB-C, --cvs-exclude\fP" This is a useful shorthand for excluding a -broad range of files that you often don\&'t want to transfer between +broad range of files that you often don\'t want to transfer between systems\&. It uses the same algorithm that CVS uses to determine if a file should be ignored\&. .IP @@ -676,7 +758,7 @@ flash-cutover when all files have been successfully transferred (for example by moving directories around and removing the old directory, although this requires also doing the transfer with -I to avoid skipping -files that haven\&'t changed)\&. This option increases the usefulness of +files that haven\'t changed)\&. This option increases the usefulness of --partial because partially transferred files will remain in the new temporary destination until they have a chance to be completed\&. If DIR is a relative path, it is relative to the destination directory\&. @@ -741,7 +823,7 @@ a remote shell transport\&. If -e or --rsh are not specified or are set to the default "rsh", this defaults to blocking IO, otherwise it defaults to non-blocking IO\&. You may find the --blocking-io option is needed for some -remote shells that can\&'t handle non-blocking IO\&. Ssh prefers blocking IO\&. +remote shells that can\'t handle non-blocking IO\&. Ssh prefers blocking IO\&. .IP .IP "\fB--log-format=FORMAT\fP" This allows you to specify exactly what the @@ -847,7 +929,7 @@ .IP o if the pattern contains a / (not counting a trailing /) then it is matched against the full filename, including any leading -directory\&. If the pattern doesn\&'t contain a / then it is matched +directory\&. If the pattern doesn\'t contain a / then it is matched only against the final component of the filename\&. Again, remember that the algorithm is applied recursively so "full filename" can actually be any portion of a path\&. @@ -869,12 +951,12 @@ The +/- rules are most useful in exclude lists, allowing you to have a single exclude list that contains both include and exclude options\&. .PP -If you end an exclude list with --exclude \&'*\&', note that since the +If you end an exclude list with --exclude \'*\', note that since the algorithm is applied recursively that unless you explicitly include parent directories of files you want to include then the algorithm will stop at the parent directories and never see the files below -them\&. To include all directories, use --include \&'*/\&' before the ---exclude \&'*\&'\&. +them\&. To include all directories, use --include \'*/\' before the +--exclude \'*\'\&. .PP Here are some exclude/include examples: .PP @@ -1020,7 +1102,7 @@ are used to determine the default username sent to a rsync server\&. .IP .IP "\fBHOME\fP" -The HOME environment variable is used to find the user\&'s +The HOME environment variable is used to find the user\'s default \&.cvsignore file\&. .IP .PP @@ -1070,7 +1152,7 @@ .SH "THANKS" .PP Thanks to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell -and David Bell for helpful suggestions and testing of rsync\&. I\&'ve +and David Bell for helpful suggestions and testing of rsync\&. I\'ve probably missed some people, my apologies if I have\&. .PP .SH "AUTHOR" Index: rsync.yo =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/rsync.yo,v retrieving revision 1.1.1.5 retrieving revision 1.4 diff -u -b -r1.1.1.5 -r1.4 --- rsync.yo 2001/12/03 23:49:01 1.1.1.5 +++ rsync.yo 2001/12/04 00:10:39 1.4 @@ -42,7 +42,7 @@ manpagesection(GENERAL) -There are six different ways of using rsync. They are: +There are eight different ways of using rsync. They are: itemize( it() for copying local files. This is invoked when neither @@ -65,6 +65,18 @@ server. This is invoked when the destination path contains a :: separator. + it() for copying from a remote machine using a remote shell + program as the transport, using rsync server on the remote + machine. This is invoked when the source path contains a :: + separator and the --rsh=COMMAND (aka "-e COMMAND") option is + also provided. + + it() for copying from the local machine to a remote machine + using a remote shell program as the transport, using rsync + server on the remote machine. This is invoked when the + destination path contains a :: separator and the + --rsh=COMMMAND option is also provided. + it() for listing files on a remote machine. This is done the same way as rsync transfers except that you leave off the local destination. @@ -139,7 +151,7 @@ transport. In this case you will connect to a remote rsync server running on TCP port 873. -You may establish the connetcion via a web proxy by setting the +You may establish the connection via a web proxy by setting the environment variable RSYNC_PROXY to a hostname:port pair pointing to your web proxy. Note that your web proxy must allow proxying to port 873, this must be configured in your proxy servers ruleset. @@ -170,12 +182,59 @@ WARNING: On some systems environment variables are visible to all users. On those systems using --password-file is recommended. +manpagesection(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM) + +It is sometimes useful to be able to set up file transfers using rsync +server capabilities on the remote machine, while still using rsh or +ssh for transport. This is especially useful when you want to connect +to a remote machine via ssh (for encryption or to get through a +firewall), but you still want to have access to the rsync server +features (see RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM, +below). + +From the user's perspective, using rsync in this way is the same as +using it to connect to an rsync server, except that you must +explicitly set the remote shell program on the command line with +--rsh=COMMAND. (Setting RSYNC_RSH in the environment will not turn on +this functionality.) + +In order to distinguish between the remote-shell user and the rsync +server user, you can use '-l user' on your remote-shell command: + +quote(rsync -av --rsh="ssh -l ssh-user" rsync-user@host::module[/path] local-path) + +The "ssh-user" will be used at the ssh level; the "rsync-user" will be +used to check against the rsyncd.conf on the remote host. + manpagesection(RUNNING AN RSYNC SERVER) An rsync server is configured using a config file which by default is called /etc/rsyncd.conf. Please see the rsyncd.conf(5) man page for more information. +manpagesection(RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM) + +See the rsyncd.conf(5) man page for full information on the rsync +server configuration file. + +Several configuration options will not be available unless the remote +user is root (e.g. chroot, setuid/setgid, etc.). There is no need to +configure inetd or the services map to include the rsync server port +if you run an rsync server only via a remote shell program. + +To run an rsync server out of a single-use ssh key, use the +"command=em(COMMAND)" syntax in the remote user's +authorized_keys entry, where command would be + +quote(rsync --server --daemon .) + +NOTE: rsync's argument parsing expects the trailing ".", so make sure +that it's there. If you want to use a rsyncd.conf(5)-style +configuration file other than /etc/rsyncd.conf, you can added a +--config-file option to the em(command): + +quote(rsync --server --daemon --config-file=em(file) .) + manpagesection(EXAMPLES) Here are some examples of how I use rsync. @@ -501,8 +560,21 @@ remote copies of rsync. By default, rsync will use rsh, but you may like to instead use ssh because of its high security. +If this option is used with bf([user@]host::module/path), then the +remote shell em(COMMMAND) will be used to run an rsync server on the +remote host, and all data will be transmitted through that remote +shell connection, rather than through a direct socket connection to a +running rsync server on the remote host. + You can also choose the remote shell program using the RSYNC_RSH environment variable. + +In either case, rsync will tokenize the remote-shell command, so you +can use constructions like + +quote(rsync [options] --rsh="ssh -l user -i identity" source dest) + +to control things at a fine level. See also the --blocking-io option which is affected by this option. Index: rsyncd.conf.5 =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/rsyncd.conf.5,v retrieving revision 1.1.1.5 retrieving revision 1.3 diff -u -b -r1.1.1.5 -r1.3 --- rsyncd.conf.5 2001/12/03 23:48:52 1.1.1.5 +++ rsyncd.conf.5 2001/12/04 00:10:39 1.3 @@ -238,6 +238,11 @@ "secrets file" option\&. The default is for all users to be able to connect without a password (this is called "anonymous rsync")\&. .IP +See also the \fBCONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL +PROGRAM\fP section in rsync(1) for information on how handle an +rsyncd\&.conf-level username that differs from the remote-shell-level +username when using a remote shell to connect to a rsync server\&. +.IP .IP "\fBsecrets file\fP" The "secrets file" option specifies the name of a file that contains the username:password pairs used for Index: rsyncd.conf.yo =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/rsyncd.conf.yo,v retrieving revision 1.1.1.5 retrieving revision 1.3 diff -u -b -r1.1.1.5 -r1.3 --- rsyncd.conf.yo 2001/12/03 23:49:02 1.1.1.5 +++ rsyncd.conf.yo 2001/12/04 00:10:39 1.3 @@ -219,6 +219,11 @@ "secrets file" option. The default is for all users to be able to connect without a password (this is called "anonymous rsync"). +See also the bf(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL +PROGRAM) section in rsync(1) for information on how handle an +rsyncd.conf-level username that differs from the remote-shell-level +username when using a remote shell to connect to a rsync server. + dit(bf(secrets file)) The "secrets file" option specifies the name of a file that contains the username:password pairs used for authenticating this module. This file is only consulted if the "auth Index: socket.c =================================================================== RCS file: /juno/repository/usr/local/pkg/rsync/socket.c,v retrieving revision 1.1.1.5 retrieving revision 1.3 diff -u -b -r1.1.1.5 -r1.3 --- socket.c 2001/12/03 23:49:04 1.1.1.5 +++ socket.c 2001/12/04 00:10:39 1.3 @@ -349,7 +349,7 @@ } -void start_accept_loop(int port, int (*fn)(int )) +void start_accept_loop(int port, int (*fn)(int, int)) { int s; extern char *bind_address; @@ -407,7 +407,7 @@ /* open log file in child before possibly giving up privileges */ log_open(); - _exit(fn(fd)); + _exit(fn(fd, fd)); } close(fd);