static int path_failure(int f_out, const char *dir, BOOL was_chdir)
{
if (was_chdir)
- rsyserr(FLOG, errno, "chdir %s failed\n", dir);
+ rsyserr(FLOG, errno, "chdir %s failed", dir);
else
rprintf(FLOG, "normalize_path(%s) failed\n", dir);
io_printf(f_out, "@ERROR: chdir failed\n");
if (!change_dir(module_chdir, CD_NORMAL))
return path_failure(f_out, module_chdir, True);
- if (module_dirlen || !use_chroot)
+ if (module_dirlen || (!use_chroot && !*lp_daemon_chroot()))
sanitize_paths = 1;
if ((munge_symlinks = lp_munge_symlinks(i)) < 0)
{
char line[1024];
const char *addr, *host;
+ char *p;
int i;
io_set_sock_fds(f_in, f_out);
if (!load_config(0))
exit_cleanup(RERR_SYNTAX);
+ p = lp_daemon_chroot();
+ if (*p) {
+ log_init(0); /* Make use we've initialized syslog before chrooting. */
+ if (chroot(p) < 0 || chdir("/") < 0) {
+ rsyserr(FLOG, errno, "daemon chroot %s failed", p);
+ return -1;
+ }
+ }
+ p = lp_daemon_gid();
+ if (*p) {
+ gid_t gid;
+ if (!group_to_gid(p, &gid, True)) {
+ rprintf(FLOG, "Invalid daemon gid: %s\n", p);
+ return -1;
+ }
+ if (setgid(gid) < 0) {
+ rsyserr(FLOG, errno, "Unable to set group to daemon gid %ld", (long)gid);
+ return -1;
+ }
+ }
+ p = lp_daemon_uid();
+ if (*p) {
+ uid_t uid;
+ if (!user_to_uid(p, &uid, True)) {
+ rprintf(FLOG, "Invalid daemon uid: %s\n", p);
+ return -1;
+ }
+ if (setuid(uid) < 0) {
+ rsyserr(FLOG, errno, "Unable to set user to daemon uid %ld", (long)uid);
+ return -1;
+ }
+ }
+
addr = client_addr(f_in);
host = lp_reverse_lookup(-1) ? client_name(f_in) : undetermined_hostname;
rprintf(FLOG, "connect from %s (%s)\n", host, addr);
/* This structure describes global (ie., server-wide) parameters. */
typedef struct {
char *bind_address;
+ char *daemon_chroot;
+ char *daemon_gid;
+ char *daemon_uid;
char *motd_file;
char *pid_file;
char *socket_options;
/* ==== global_vars ==== */
{
/* bind_address; */ NULL,
+ /* daemon_chroot; */ NULL,
+ /* daemon_gid; */ NULL,
+ /* daemon_uid; */ NULL,
/* motd_file; */ NULL,
/* pid_file; */ NULL,
/* socket_options; */ NULL,
static struct parm_struct parm_table[] =
{
{"address", P_STRING, P_GLOBAL,&Vars.g.bind_address, NULL,0},
+ {"daemon chroot", P_STRING, P_GLOBAL,&Vars.g.daemon_chroot, NULL,0},
+ {"daemon gid", P_STRING, P_GLOBAL,&Vars.g.daemon_gid, NULL,0},
+ {"daemon uid", P_STRING, P_GLOBAL,&Vars.g.daemon_uid, NULL,0},
{"listen backlog", P_INTEGER,P_GLOBAL,&Vars.g.listen_backlog, NULL,0},
{"motd file", P_STRING, P_GLOBAL,&Vars.g.motd_file, NULL,0},
{"pid file", P_STRING, P_GLOBAL,&Vars.g.pid_file, NULL,0},
int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
FN_GLOBAL_STRING(lp_bind_address, &Vars.g.bind_address)
+FN_GLOBAL_STRING(lp_daemon_chroot, &Vars.g.daemon_chroot)
+FN_GLOBAL_STRING(lp_daemon_gid, &Vars.g.daemon_gid)
+FN_GLOBAL_STRING(lp_daemon_uid, &Vars.g.daemon_uid)
FN_GLOBAL_STRING(lp_motd_file, &Vars.g.motd_file)
FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file)
FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options)
had omitted the dot-dir, the chroot would have used the whole path, and the
inside-chroot path would have been "/".
-When "use chroot" is false or the inside-chroot path is not "/", rsync will:
-(1) munge symlinks by
+When both "use chroot" and "daemon chroot" are false, OR the inside-chroot path
+of "use chroot" is not "/", rsync will: (1) munge symlinks by
default for security reasons (see "munge symlinks" for a way to turn this
off, but only if you trust your users), (2) substitute leading slashes in
absolute paths with the module's path (so that options such as
chroot area that is different from your normal system. For example, you
could abbreviate the list of users and groups.
+dit(bf(daemon chroot)) This parameter specifies a path to which the daemon will
+chroot before beginning communication with clients. Module paths (and any "use
+chroot" settings) will then be related to this one. This lets you choose if you
+want the whole daemon to be chrooted (with this setting), just the transfers to
+be chrooted (with "use chroot"), or both. Keep in mind that the "daemon chroot"
+area may need various OS/lib/etc files installed to allow the daemon to function.
+By default the daemon runs without any chrooting.
+
dit(bf(numeric ids)) Enabling this parameter disables the mapping
of users and groups by name for the current daemon module. This prevents
the daemon from trying to load any user/group-related files or libraries.
bf(--munge-links) command-line option (using a method described below).
This should help protect your files from user trickery when
your daemon module is writable. The default is disabled when "use chroot"
-is on and the inside-chroot path is "/", otherwise it is enabled.
+is on with an inside-chroot path of "/", OR if "daemon chroot" is on,
+otherwise it is enabled.
If you disable this parameter on a daemon that is not read-only, there
are tricks that a user can play with uploaded symlinks to access
group attributes (and indeed, your OS may not allow a non-super-user to try to
change their group settings).
+dit(bf(daemon uid)) This parameter specifies a uid under which the daemon will
+run. The daemon usually runs as user root, and when this is left unset the user
+is left unchanged. See also the "uid" parameter.
+
+dit(bf(daemon gid)) This parameter specifies a gid under which the daemon will
+run. The daemon usually runs as group root, and when this is left unset, the
+group is left unchanged. See also the "gid" parameter.
+
dit(bf(fake super)) Setting "fake super = yes" for a module causes the
daemon side to behave as if the bf(--fake-super) command-line option had
been specified. This allows the full attributes of a file to be stored