X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/0b515981fcfb4ba60d6f01ab604d11e13b85e48f..ec8637f3679b891041c798400774141024e24a4e:/clientserver.c diff --git a/clientserver.c b/clientserver.c index d16e5617..1e3af63a 100644 --- a/clientserver.c +++ b/clientserver.c @@ -20,9 +20,10 @@ */ #include "rsync.h" +#include "ifuncs.h" extern int verbose; -extern int quiet; +extern int dry_run; extern int output_motd; extern int list_only; extern int am_sender; @@ -39,6 +40,7 @@ extern int remote_protocol; extern int protocol_version; extern int io_timeout; extern int no_detach; +extern int write_batch; extern int default_af_hint; extern int logfile_format_has_i; extern int logfile_format_has_o_or_i; @@ -56,6 +58,7 @@ extern char curr_dir[]; char *auth_user; int read_only = 0; int module_id = -1; +int munge_symlinks = 0; struct chmod_mode_struct *daemon_chmod_modes; /* module_dirlen is the length of the module_dir string when in daemon @@ -192,21 +195,31 @@ static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]) { - int i; + int i, modlen; char line[BIGPATHBUFLEN]; char *sargs[MAX_ARGS]; int sargc = 0; - char *p, *path = *argv; + char *p, *modname; - if (argc == 0 && !am_sender) - list_only |= 1; + assert(argc > 0); - if (*path == '/') { + if (**argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name\n"); return -1; } + if (!(p = strchr(*argv, '/'))) + modlen = strlen(*argv); + else + modlen = p - *argv; + + if (!(modname = new_array(char, modlen+1+1))) /* room for '/' & '\0' */ + out_of_memory("start_inband_exchange"); + strlcpy(modname, *argv, modlen + 1); + modname[modlen] = '/'; + modname[modlen+1] = '\0'; + if (!user) user = getenv("USER"); if (!user) @@ -215,9 +228,6 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0) return -1; - if (list_only && protocol_version >= 29) - list_only |= 2; - /* 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 */ @@ -235,7 +245,12 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n"); exit_cleanup(RERR_SYNTAX); } - sargs[sargc++] = *argv++; + if (list_only && strncmp(*argv, modname, modlen) == 0 + && argv[0][modlen] == '\0') + sargs[sargc++] = modname; /* we send "modname/" */ + else + sargs[sargc++] = *argv; + argv++; argc--; } @@ -244,10 +259,7 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char if (verbose > 1) print_child_argv("sending daemon args:", sargs); - p = strchr(path, '/'); - if (p) *p = '\0'; - io_printf(f_out, "%s\n", path); - if (p) *p = '/'; + io_printf(f_out, "%.*s\n", modlen, modname); /* Old servers may just drop the connection here, rather than sending a proper EXIT command. Yuck. */ @@ -306,6 +318,8 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char io_start_multiplex_in(); } + free(modname); + return 0; } @@ -341,8 +355,12 @@ static int read_arg_from_pipe(int fd, char *buf, int limit) char *bp = buf, *eob = buf + limit - 1; while (1) { - if (read(fd, bp, 1) != 1) + int got = read(fd, bp, 1); + if (got != 1) { + if (got < 0 && errno == EINTR) + continue; return -1; + } if (*bp == '\0') break; if (bp < eob) @@ -611,6 +629,18 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) sanitize_paths = 1; } + if ((munge_symlinks = lp_munge_symlinks(i)) < 0) + munge_symlinks = !use_chroot; + if (munge_symlinks) { + STRUCT_STAT st; + if (stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) { + rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n", + SYMLINK_PREFIX); + io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name); + exit_cleanup(RERR_UNSUPPORTED); + } + } + if (am_root) { /* XXXX: You could argue that if the daemon is started * by a non-root user and they explicitly specify a @@ -670,6 +700,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) am_server = 1; /* Don't let someone try to be tricky. */ if (lp_ignore_errors(module_id)) ignore_errors = 1; + if (write_batch < 0) + dry_run = 1; if (lp_fake_super(i)) am_root = -1; @@ -839,9 +871,70 @@ int start_daemon(int f_in, int f_out) return rsync_module(f_in, f_out, i, addr, host); } +static void create_pid_file(void) +{ + char *pid_file = lp_pid_file(); + char pidbuf[16]; + pid_t pid = getpid(); + int fd; + + if (!pid_file || !*pid_file) + return; + + cleanup_set_pid(pid); + if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666 & ~orig_umask)) == -1) { + cleanup_set_pid(0); + fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno)); + rsyserr(FLOG, errno, "failed to create pid file %s", pid_file); + exit_cleanup(RERR_FILEIO); + } + snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid); + write(fd, pidbuf, strlen(pidbuf)); + close(fd); +} + +/* Become a daemon, discarding the controlling terminal. */ +static void become_daemon(void) +{ + int i; + pid_t pid = fork(); + + if (pid) { + if (pid < 0) { + fprintf(stderr, "failed to fork: %s\n", strerror(errno)); + exit_cleanup(RERR_FILEIO); + } + _exit(0); + } + + create_pid_file(); + + /* detach from the terminal */ +#ifdef HAVE_SETSID + setsid(); +#elif defined TIOCNOTTY + i = open("/dev/tty", O_RDWR); + if (i >= 0) { + ioctl(i, (int)TIOCNOTTY, (char *)0); + close(i); + } +#endif + /* make sure that stdin, stdout an stderr don't stuff things + * up (library functions, for example) */ + for (i = 0; i < 3; i++) { + close(i); + open("/dev/null", O_RDWR); + } +} + int daemon_main(void) { - char *pid_file; + if (!config_file) { + if (am_server && am_root <= 0) + config_file = RSYNCD_USERCONF; + else + config_file = RSYNCD_SYSCONF; + } if (is_a_socket(STDIN_FILENO)) { int i; @@ -857,11 +950,15 @@ int daemon_main(void) return start_daemon(STDIN_FILENO, STDIN_FILENO); } - if (!no_detach) - become_daemon(); - - if (!lp_load(config_file, 1)) + if (!lp_load(config_file, 1)) { + fprintf(stderr, "Failed to parse config file: %s\n", config_file); exit_cleanup(RERR_SYNTAX); + } + + if (no_detach) + create_pid_file(); + else + become_daemon(); if (rsync_port == 0 && (rsync_port = lp_rsync_port()) == 0) rsync_port = RSYNC_PORT; @@ -876,23 +973,6 @@ int daemon_main(void) * address too. In fact, why not just do inet_ntop on the * local address??? */ - if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) { - char pidbuf[16]; - int fd; - pid_t pid = getpid(); - cleanup_set_pid(pid); - if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC, - 0666 & ~orig_umask)) == -1) { - cleanup_set_pid(0); - rsyserr(FLOG, errno, "failed to create pid file %s", - pid_file); - exit_cleanup(RERR_FILEIO); - } - snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid); - write(fd, pidbuf, strlen(pidbuf)); - close(fd); - } - start_accept_loop(rsync_port, start_daemon); return -1; }