*
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 2001-2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2002-2008 Wayne Davison
+ * Copyright (C) 2002-2009 Wayne Davison
*
* 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
*/
#include "rsync.h"
-#include "ifuncs.h"
+#include "itypes.h"
extern int quiet;
extern int dry_run;
char *module_dir = NULL;
unsigned int module_dirlen = 0;
+char *full_module_path;
+
static int rl_nulls = 0;
#ifdef HAVE_SIGACTION
static struct sigaction sigact;
#endif
+/* Used when "reverse lookup" is off. */
+const char undetermined_hostname[] = "UNDETERMINED";
+
/**
* Run a client connected to an rsyncd. The alternative to this
* function for remote-shell connections is do_cmd().
return bp - buf;
}
-static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
+static int path_failure(int f_out, const char *dir, BOOL was_chdir)
+{
+ if (was_chdir)
+ rsyserr(FLOG, errno, "chdir %s failed\n", dir);
+ else
+ rprintf(FLOG, "normalize_path(%s) failed\n", dir);
+ io_printf(f_out, "@ERROR: chdir failed\n");
+ return -1;
+}
+
+static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host)
{
int argc;
- char **argv, **orig_argv, **orig_early_argv, *chroot_path = NULL;
+ char **argv, **orig_argv, **orig_early_argv, *module_chdir;
char line[BIGPATHBUFLEN];
uid_t uid = (uid_t)-2; /* canonically "nobody" */
gid_t gid = (gid_t)-2;
iconv_opt = NULL;
#endif
+ /* If reverse lookup is disabled globally but enabled for this module,
+ * we need to do it now before the access check. */
+ if (host == undetermined_hostname && lp_reverse_lookup(i))
+ host = client_name(f_in);
+
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
rprintf(FLOG, "rsync denied on module %s from %s (%s)\n",
name, host, addr);
module_dir = lp_path(i);
if (use_chroot) {
if ((p = strstr(module_dir, "/./")) != NULL) {
- *p = '\0';
- p += 2;
- } else if ((p = strdup("/")) == NULL) /* MEMORY LEAK */
- out_of_memory("rsync_module");
- }
-
- /* We do a change_dir() that doesn't actually call chdir()
- * just to make a relative path absolute. */
- strlcpy(line, curr_dir, sizeof line);
- if (!change_dir(module_dir, CD_SKIP_CHDIR))
- goto chdir_failed;
- if (strcmp(curr_dir, module_dir) != 0
- && (module_dir = strdup(curr_dir)) == NULL)
- out_of_memory("rsync_module");
- change_dir(line, CD_SKIP_CHDIR); /* Restore curr_dir. */
-
- if (use_chroot) {
- chroot_path = module_dir;
- module_dir = p; /* p is "/" or our inside-chroot path */
+ *p = '\0'; /* Temporary... */
+ if (!(module_chdir = normalize_path(module_dir, True, NULL)))
+ return path_failure(f_out, module_dir, False);
+ *p = '/';
+ if (!(p = normalize_path(p + 2, True, &module_dirlen)))
+ return path_failure(f_out, strstr(module_dir, "/./"), False);
+ if (!(full_module_path = normalize_path(module_dir, False, NULL)))
+ full_module_path = module_dir;
+ module_dir = p;
+ } else {
+ if (!(module_chdir = normalize_path(module_dir, False, NULL)))
+ return path_failure(f_out, module_dir, False);
+ full_module_path = module_chdir;
+ module_dir = "/";
+ module_dirlen = 1;
+ }
+ } else {
+ if (!(module_chdir = normalize_path(module_dir, False, &module_dirlen)))
+ return path_failure(f_out, module_dir, False);
+ full_module_path = module_dir = module_chdir;
}
- module_dirlen = clean_fname(module_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
if (module_dirlen == 1) {
module_dirlen = 0;
char *modname, *modpath, *hostaddr, *hostname, *username;
int status;
- if (!use_chroot)
- p = module_dir;
- else if (module_dirlen) {
- pathjoin(line, sizeof line, chroot_path, module_dir+1);
- p = line;
- } else
- p = chroot_path;
-
if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
- || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", p) < 0
+ || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", full_module_path) < 0
|| asprintf(&hostaddr, "RSYNC_HOST_ADDR=%s", addr) < 0
|| asprintf(&hostname, "RSYNC_HOST_NAME=%s", host) < 0
|| asprintf(&username, "RSYNC_USER_NAME=%s", auth_user) < 0)
status = -1;
if (asprintf(&p, "RSYNC_EXIT_STATUS=%d", status) > 0)
putenv(p);
- system(lp_postxfer_exec(i));
+ if (system(lp_postxfer_exec(i)) < 0)
+ status = -1;
_exit(status);
}
}
* a warning, unless a "require chroot" flag is set,
* in which case we fail.
*/
- if (chroot(chroot_path)) {
- rsyserr(FLOG, errno, "chroot %s failed", chroot_path);
+ if (chroot(module_chdir)) {
+ rsyserr(FLOG, errno, "chroot %s failed", module_chdir);
io_printf(f_out, "@ERROR: chroot failed\n");
return -1;
}
- if (!change_dir(module_dir, CD_NORMAL))
- goto chdir_failed;
- if (module_dirlen)
- sanitize_paths = 1;
- } else {
- if (!change_dir(module_dir, CD_NORMAL)) {
- chdir_failed:
- rsyserr(FLOG, errno, "chdir %s failed\n", module_dir);
- io_printf(f_out, "@ERROR: chdir failed\n");
- return -1;
- }
- sanitize_paths = 1;
+ module_chdir = module_dir;
}
+ if (!change_dir(module_chdir, CD_NORMAL))
+ return path_failure(f_out, module_chdir, True);
+ if (module_dirlen || !use_chroot)
+ sanitize_paths = 1;
+
if ((munge_symlinks = lp_munge_symlinks(i)) < 0)
munge_symlinks = !use_chroot || module_dirlen;
if (munge_symlinks) {
int start_daemon(int f_in, int f_out)
{
char line[1024];
- char *addr, *host;
+ const char *addr, *host;
int i;
io_set_sock_fds(f_in, f_out);
exit_cleanup(RERR_SYNTAX);
addr = client_addr(f_in);
- host = client_name(f_in);
+ host = lp_reverse_lookup(-1) ? client_name(f_in) : undetermined_hostname;
rprintf(FLOG, "connect from %s (%s)\n", host, addr);
if (!am_server) {
char *pid_file = lp_pid_file();
char pidbuf[16];
pid_t pid = getpid();
- int fd;
+ int fd, len;
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) {
+ failure:
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));
+ len = strlen(pidbuf);
+ if (write(fd, pidbuf, len) != len)
+ goto failure;
close(fd);
}