Add "use chroot" and "pid file" rsyncd.conf options. The former allows one
authorDavid Dykstra <dwd@samba.org>
Mon, 26 Oct 1998 21:51:47 +0000 (21:51 +0000)
committerDavid Dykstra <dwd@samba.org>
Mon, 26 Oct 1998 21:51:47 +0000 (21:51 +0000)
to disable the use of chroot so rsync --daemon can be run as a non-root
user (if a non-privileged --port is used).  The latter allows one to
specify a file in which to write the process id of the daemon, which is
useful when rsync --daemon is not run from inetd.

cleanup.c
clientserver.c
loadparm.c
main.c
rsyncd.conf.yo

index 57fce18..abd7b0d 100644 (file)
--- a/cleanup.c
+++ b/cleanup.c
@@ -29,6 +29,7 @@ static char *cleanup_new_fname;
 static struct file_struct *cleanup_file;
 static int cleanup_fd1, cleanup_fd2;
 static struct map_struct *cleanup_buf;
+static int cleanup_pid = 0;
 
 void exit_cleanup(int code)
 {
@@ -50,6 +51,8 @@ void exit_cleanup(int code)
        if (code) {
                kill_all(SIGUSR1);
        }
+       if ((cleanup_pid != 0) && (cleanup_pid == (int) getpid()))
+               unlink(lp_pid_file());
        exit(code);
 }
 
@@ -70,3 +73,8 @@ void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
        cleanup_fd1 = fd1;
        cleanup_fd2 = fd2;
 }
+
+void cleanup_set_pid(int pid)
+{
+       cleanup_pid = pid;
+}
index cf10b12..debc4fe 100644 (file)
@@ -122,6 +122,7 @@ static int rsync_module(int fd, int i)
        char *host = client_name(fd);
        char *name = lp_name(i);
        char *user;
+       int use_chroot = lp_use_chroot(i);
        int start_glob=0;
        int ret;
        char *request=NULL;
@@ -194,28 +195,37 @@ static int rsync_module(int fd, int i)
 
        log_open();
 
-       if (chroot(lp_path(i))) {
-               rprintf(FERROR,"chroot %s failed\n", lp_path(i));
-               io_printf(fd,"@ERROR: chroot failed\n");
-               return -1;
-       }
+       if (use_chroot) {
+               if (chroot(lp_path(i))) {
+                       rprintf(FERROR,"chroot %s failed\n", lp_path(i));
+                       io_printf(fd,"@ERROR: chroot failed\n");
+                       return -1;
+               }
 
-       if (chdir("/")) {
-               rprintf(FERROR,"chdir %s failed\n", lp_path(i));
-               io_printf(fd,"@ERROR: chdir failed\n");
-               return -1;
-       }
+               if (chdir("/")) {
+                       rprintf(FERROR,"chdir %s failed\n", lp_path(i));
+                       io_printf(fd,"@ERROR: chdir failed\n");
+                       return -1;
+               }
 
-       if (setgid(gid) || getgid() != gid) {
-               rprintf(FERROR,"setgid %d failed\n", gid);
-               io_printf(fd,"@ERROR: setgid failed\n");
-               return -1;
-       }
+               if (setgid(gid) || getgid() != gid) {
+                       rprintf(FERROR,"setgid %d failed\n", gid);
+                       io_printf(fd,"@ERROR: setgid failed\n");
+                       return -1;
+               }
 
-       if (setuid(uid) || getuid() != uid) {
-               rprintf(FERROR,"setuid %d failed\n", uid);
-               io_printf(fd,"@ERROR: setuid failed\n");
-               return -1;
+               if (setuid(uid) || getuid() != uid) {
+                       rprintf(FERROR,"setuid %d failed\n", uid);
+                       io_printf(fd,"@ERROR: setuid failed\n");
+                       return -1;
+               }
+
+       } else {
+               if (!push_dir(lp_path(i), 0)) {
+                       rprintf(FERROR,"chdir %s failed\n", lp_path(i));
+                       io_printf(fd,"@ERROR: chdir failed\n");
+                       return -1;
+               }
        }
 
        am_root = (getuid() == 0);
@@ -257,6 +267,21 @@ static int rsync_module(int fd, int i)
                }
        }
 
+       if (!use_chroot) {
+               /*
+                * Note that this is applied to all parameters, whether or not
+                *    they are filenames, but no other legal parameters contain
+                *    the forms that need to be sanitized so it doesn't hurt;
+                *    it is not known at this point which parameters are files
+                *    and which aren't.
+                */
+               for (i = 1; i < argc; i++) {
+                       char *copy = sanitize_path(argv[i]);
+                       free((void *)argv[i]);
+                       argv[i] = copy;
+               }
+       }
+
        ret = parse_arguments(argc, argv);
 
        if (request) {
@@ -381,6 +406,7 @@ static int start_daemon(int fd)
 int daemon_main(void)
 {
        extern char *config_file;
+       char *pid_file;
 
        /* this ensures that we don't call getcwd after the chroot,
            which doesn't work on platforms that use popen("pwd","r")
@@ -414,6 +440,19 @@ int daemon_main(void)
 
        rprintf(FINFO,"rsyncd version %s starting\n",VERSION);
 
+       if (((pid_file = lp_pid_file()) != NULL) && (*pid_file != '\0')) {
+               FILE *f;
+               int pid = (int) getpid();
+               cleanup_set_pid(pid);
+               if ((f = fopen(lp_pid_file(), "w")) == NULL) {
+                   cleanup_set_pid(0);
+                   fprintf(stderr,"failed to create pid file %s\n", pid_file);
+                   exit_cleanup(1);
+               }
+               fprintf(f, "%d\n", pid);
+               fclose(f);
+       }
+
        start_accept_loop(rsync_port, start_daemon);
        return -1;
 }
index 24ef7c6..aba7d30 100644 (file)
@@ -99,6 +99,7 @@ typedef struct
        char *motd_file;
        char *lock_file;
        char *log_file;
+       char *pid_file;
        int syslog_facility;
        int max_connections;
        char *socket_options;
@@ -118,6 +119,7 @@ typedef struct
        char *comment;
        BOOL read_only;
        BOOL list;
+       BOOL use_chroot;
        char *uid;
        char *gid;
        char *hosts_allow;
@@ -137,6 +139,7 @@ static service sDefault =
        NULL,    /* comment */
        True,    /* read only */
        True,    /* list */
+       True,    /* use chroot */
        "nobody",/* uid */
        "nobody",/* gid */
        NULL,    /* hosts allow */
@@ -233,12 +236,14 @@ static struct parm_struct parm_table[] =
   {"syslog facility",  P_ENUM,    P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
   {"socket options",   P_STRING,  P_GLOBAL, &Globals.socket_options,NULL,  0},
   {"log file",         P_STRING,  P_GLOBAL, &Globals.log_file,      NULL,  0},
+  {"pid file",         P_STRING,  P_GLOBAL, &Globals.pid_file,      NULL,  0},
 
   {"name",             P_STRING,  P_LOCAL,  &sDefault.name,        NULL,   0},
   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,     NULL,   0},
   {"path",             P_STRING,  P_LOCAL,  &sDefault.path,        NULL,   0},
   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.read_only,   NULL,   0},
   {"list",             P_BOOL,    P_LOCAL,  &sDefault.list,        NULL,   0},
+  {"use chroot",       P_BOOL,    P_LOCAL,  &sDefault.use_chroot,  NULL,   0},
   {"uid",              P_STRING,  P_LOCAL,  &sDefault.uid,         NULL,   0},
   {"gid",              P_STRING,  P_LOCAL,  &sDefault.gid,         NULL,   0},
   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.hosts_allow, NULL,   0},
@@ -298,6 +303,7 @@ static void init_locals(void)
 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
 FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
+FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
@@ -307,6 +313,7 @@ FN_LOCAL_STRING(lp_comment, comment)
 FN_LOCAL_STRING(lp_path, path)
 FN_LOCAL_BOOL(lp_read_only, read_only)
 FN_LOCAL_BOOL(lp_list, list)
+FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
 FN_LOCAL_STRING(lp_uid, uid)
 FN_LOCAL_STRING(lp_gid, gid)
 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
diff --git a/main.c b/main.c
index c87dd7b..94e358f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -584,6 +584,7 @@ int main(int argc,char *argv[])
        signal(SIGINT,SIGNAL_CAST sig_int);
        signal(SIGPIPE,SIGNAL_CAST sig_int);
        signal(SIGHUP,SIGNAL_CAST sig_int);
+       signal(SIGTERM,SIGNAL_CAST sig_int);
 
        if (am_daemon) {
                return daemon_main();
index 9e9de5e..3725fd5 100644 (file)
@@ -94,7 +94,10 @@ exceeded. The default is tt(/var/run/rsyncd.lock).
 dit(bf(log file)) The "log file" option tells the rsync daemon to log
 messages to that file rather than using syslog. This is particularly
 useful on systems (such as AIX) where syslog() doesn't work for
-chrooted programs like rsync.
+chrooted programs.
+
+dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
+its process id to that file.
 
 dit(bf(syslog facility)) The "syslog facility" option allows you to
 specify the syslog facility name to use when logging messages from the
@@ -128,9 +131,15 @@ that is displayed next to the module name when clients obtain a list
 of available modules. The default is no comment.
 
 dit(bf(path)) The "path" option specifies the directory in the servers
-filesystem to make available in this module. The rsync server will
-chroot to this path before starting the file transfer with the
-client. You must specify this option for each module in tt(/etc/rsyncd.conf).
+filesystem to make available in this module.  You must specify this option
+for each module in tt(/etc/rsyncd.conf).
+
+dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
+to the "path" before starting the file transfer with the client.  This has
+the advantage of extra protection against possible implementation security
+holes, but it has the disadvantages of requiring super-user privileges and
+of not being able to follow symbolic links outside of the new root path.
+The default is to use chroot.
 
 dit(bf(read only)) The "read only" option determines whether clients
 will be able to upload files or not. If "read only" is true then any
@@ -272,8 +281,10 @@ A more sophisticated example would be:
 
 uid = nobody nl()
 gid = nobody nl()
+use chroot = no nl()
 max connections = 4 nl()
 syslog facility = local5 nl()
+pid file = /etc/rsyncd.pid
 
 verb([ftp]
         path = /var/ftp/pub