[SCM] The rsync repository. - branch master updated

Rsync CVS commit messages rsync-cvs at lists.samba.org
Fri Jul 17 17:47:59 UTC 2020


The branch, master has been updated
       via  7e07a325 Add the `name converter` daemon parameter.
      from  be11a496 Run a daily build.

https://git.samba.org/?p=rsync.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 7e07a325043453ca2974f199b5cdda5f858b5603
Author: Wayne Davison <wayne at opencoder.net>
Date:   Fri Jul 17 10:22:27 2020 -0700

    Add the `name converter` daemon parameter.
    
    This is based on the long-standing patch but with the protocol changed
    to just use newlines as delimiters instead of null chars (since names
    should not contain a newline AND it makes it easier to write a helper
    script).  Lots of other small improvements and a better default value
    for "numeric ids" when using "use chroot" with "name converter".

-----------------------------------------------------------------------

Summary of changes:
 NEWS.md             | 14 +++++++----
 clientserver.c      | 62 ++++++++++++++++++++++++++++++++++++++++++-----
 daemon-parm.txt     |  1 +
 rsyncd.conf.5.md    | 49 ++++++++++++++++++++++++-------------
 support/nameconvert | 50 ++++++++++++++++++++++++++++++++++++++
 uidlist.c           | 69 ++++++++++++++++++++++++++++++++++++++++-------------
 6 files changed, 202 insertions(+), 43 deletions(-)
 create mode 100755 support/nameconvert


Changeset truncated at 500 lines:

diff --git a/NEWS.md b/NEWS.md
index c83e0367..6ab53861 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -19,16 +19,22 @@
 
  - Allow `--max-alloc=0` to specify no limit to the alloc sanity check.
 
- - Allow `--block-size=SIZE` to specify the size using units such as "100K".
+ - Allow `--block-size=SIZE` to specify the size using units (e.g. "100K").
 
- - The name of the id-0 user & group is now sent to the receiver along with the
-   other user/group names in the transfer (instead of assuming that both sides
-   have the same id-0 names).
+ - The name of the id-0 user & group are now sent to the receiver along with
+   the other user/group names in the transfer (instead of assuming that both
+   sides have the same id-0 names).
 
  - Added the `--stop-after=MINS` and `--stop-at=DATE_TIME` options (with the
    `--time-limit=MINS` option accepted as an alias for `--stop-after`).  This
    is an enhanced version of the time-limit patch from the patches repo.
 
+ - Added the `name converter` daemon parameter to make it easier to convert
+   user & group names inside a chrooted daemon module.  This is based on the
+   nameconverter patch with some improvements, including a tweak to the request
+   protocol (so if you used this patch in the past, be sure to update your
+   converter script).
+
  - Added the ability to specify "@netgroup" names to the `hosts allow` and
    `hosts deny` daemon parameters.  This is a finalized version of the
    netgroup-auth patch from the patches repo.
diff --git a/clientserver.c b/clientserver.c
index 372f9ab3..f324a989 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -21,6 +21,7 @@
 
 #include "rsync.h"
 #include "itypes.h"
+#include "ifuncs.h"
 
 extern int quiet;
 extern int dry_run;
@@ -71,6 +72,7 @@ int module_id = -1;
 int pid_file_fd = -1;
 int early_input_len = 0;
 char *early_input = NULL;
+pid_t namecvt_pid = 0;
 struct chmod_mode_struct *daemon_chmod_modes;
 
 #define EARLY_INPUT_CMD "#early_input="
@@ -85,6 +87,7 @@ unsigned int module_dirlen = 0;
 char *full_module_path;
 
 static int rl_nulls = 0;
+static int namecvt_fd_req = -1, namecvt_fd_ans = -1;
 
 #ifdef HAVE_SIGACTION
 static struct sigaction sigact;
@@ -425,7 +428,7 @@ void set_env_num(const char *var, long num)
 }
 #endif
 
-/* Used for both early exec & pre-xfer exec */
+/* Used for "early exec", "pre-xfer exec", and the "name converter" script. */
 static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
 {
 	int arg_fds[2], error_fds[2], arg_fd;
@@ -492,7 +495,7 @@ static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
 	return pid;
 }
 
-static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv, int am_early)
+static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv, int exec_type)
 {
 	int j = 0;
 
@@ -511,10 +514,11 @@ static void write_pre_exec_args(int write_fd, char *request, char **early_argv,
 	}
 	write_byte(write_fd, 0);
 
-	if (am_early && early_input_len)
+	if (exec_type == 1 && early_input_len)
 		write_buf(write_fd, early_input, early_input_len);
 
-	close(write_fd);
+	if (exec_type != 2) /* the name converter needs this left open */
+		close(write_fd);
 }
 
 static char *finish_pre_exec(const char *desc, pid_t pid, int read_fd)
@@ -811,7 +815,8 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 	log_init(1);
 
 #ifdef HAVE_PUTENV
-	if ((*lp_early_exec(module_id) || *lp_prexfer_exec(module_id) || *lp_postxfer_exec(module_id))
+	if ((*lp_early_exec(module_id) || *lp_prexfer_exec(module_id)
+	  || *lp_postxfer_exec(module_id) || *lp_name_converter(module_id))
 	 && !getenv("RSYNC_NO_XFER_EXEC")) {
 		set_env_num("RSYNC_PID", (long)getpid());
 
@@ -873,6 +878,15 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 				return -1;
 			}
 		}
+
+		if (*lp_name_converter(module_id)) {
+			namecvt_pid = start_pre_exec(lp_name_converter(module_id), &namecvt_fd_req, &namecvt_fd_ans);
+			if (namecvt_pid == (pid_t)-1) {
+				rsyserr(FLOG, errno, "name-converter exec preparation failed");
+				io_printf(f_out, "@ERROR: name-converter exec preparation failed\n");
+				return -1;
+			}
+		}
 	}
 #endif
 
@@ -1004,6 +1018,9 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 		err_msg = finish_pre_exec("pre-xfer exec", pre_exec_pid, pre_exec_error_fd);
 	}
 
+	if (namecvt_pid)
+		write_pre_exec_args(namecvt_fd_req, request, orig_early_argv, orig_argv, 2);
+
 	if (orig_early_argv)
 		free(orig_early_argv);
 
@@ -1100,7 +1117,8 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 #endif
 
 	if (!numeric_ids
-	 && (use_chroot ? lp_numeric_ids(module_id) != False : lp_numeric_ids(module_id) == True))
+	 && (use_chroot ? lp_numeric_ids(module_id) != False && !*lp_name_converter(module_id)
+		        : lp_numeric_ids(module_id) == True))
 		numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */
 
 	if (lp_timeout(module_id) && (!io_timeout || lp_timeout(module_id) < io_timeout))
@@ -1124,6 +1142,38 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 	return 0;
 }
 
+BOOL namecvt_call(const char *cmd, const char **name_p, id_t *id_p)
+{
+	char buf[1024];
+	int got, len;
+
+	if (*name_p)
+		len = snprintf(buf, sizeof buf, "%s %s\n", cmd, *name_p);
+	else
+		len = snprintf(buf, sizeof buf, "%s %ld\n", cmd, (long)*id_p);
+	if (len >= (int)sizeof buf) {
+		rprintf(FERROR, "namecvt_call() request was too large.\n");
+		exit_cleanup(RERR_UNSUPPORTED);
+	}
+
+	while ((got = write(namecvt_fd_req, buf, len)) != len) {
+		if (got < 0 && errno == EINTR)
+			continue;
+		rprintf(FERROR, "Connection to name-converter failed.\n");
+		exit_cleanup(RERR_SOCKETIO);
+	}
+
+	if (!read_line_old(namecvt_fd_ans, buf, sizeof buf, 0))
+		return False;
+
+	if (*name_p)
+		*id_p = (id_t)atol(buf);
+	else
+		*name_p = strdup(buf);
+
+	return True;
+}
+
 /* send a list of available modules to the client. Don't list those
    with "list = False". */
 static void send_listing(int fd)
diff --git a/daemon-parm.txt b/daemon-parm.txt
index 0f8f01e5..3b438b02 100644
--- a/daemon-parm.txt
+++ b/daemon-parm.txt
@@ -33,6 +33,7 @@ STRING	lock_file		DEFAULT_LOCK_FILE
 STRING	log_file		NULL
 STRING	log_format		"%o %h [%a] %m (%u) %f %l"
 STRING	name			NULL
+STRING	name_converter		NULL
 STRING	outgoing_chmod		NULL
 STRING	post-xfer_exec		NULL
 STRING	pre-xfer_exec		NULL
diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md
index 8b696b40..b70532b1 100644
--- a/rsyncd.conf.5.md
+++ b/rsyncd.conf.5.md
@@ -207,21 +207,18 @@ the values of parameters.  See the GLOBAL PARAMETERS section for more details.
     they would escape the module hierarchy.  The default for "use chroot" is
     true, and is the safer choice (especially if the module is not read-only).
 
-    When this parameter is enabled, the "numeric-ids" option will also default
-    to being enabled (disabling name lookups).  See below for what a chroot
-    needs in order for name lookups to succeed.
+    When this parameter is enabled *and* the "name converter" parameter is
+    *not* set, the "numeric ids" parameter will default to being enabled
+    (disabling name lookups).  This means that if you manually setup
+    name-lookup libraries in your chroot (instead of using a name converter)
+    that you need to explicitly set `numeric ids = false` for rsync to do name
+    lookups.
 
     If you copy library resources into the module's chroot area, you should
     protect them through your OS's normal user/group or ACL settings (to
     prevent the rsync module's user from being able to change them), and then
     hide them from the user's view via "exclude" (see how in the discussion of
-    that parameter).  At that point it will be safe to enable the mapping of
-    users and groups by name using the "numeric ids" daemon parameter (see
-    below).
-
-    Note also that you are free to setup custom user/group information in the
-    chroot area that is different from your normal system.  For example, you
-    could abbreviate the list of users and groups.
+    that parameter).  However, it's easier and safer to setup a name converter.
 
 0.  `daemon chroot`
 
@@ -258,6 +255,27 @@ the values of parameters.  See the GLOBAL PARAMETERS section for more details.
     others, then you will need to setup multiple rsync daemon processes on
     different ports.
 
+0.  `name converter`
+
+    This parameter lets you specify a program that will be run by the rsync
+    daemon to do user & group conversions between names & ids.  This script
+    is started prior to any chroot being setup, and runs as the daemon user
+    (not the transfer user).  You can specify a fully qualified pathname or
+    a program name that is on the $PATH.
+
+    The program can be used to do normal user & group lookups without having to
+    put any extra files into the chroot area of the module *or* you can do
+    customized conversions.
+
+    The nameconvert program has access to all of the environment variables that
+    are described in the section on `pre-xfer exec`.  This is useful if you
+    want to customize the conversion using information about the module and/or
+    the copy request.
+
+    There is a sample python script in the support dir named "nameconvert" that
+    implements the normal user & group lookups.  Feel free to customize it or
+    just use it as documentation to implement your own.
+
 0.  `numeric ids`
 
     Enabling this parameter disables the mapping of users and groups by name
@@ -269,13 +287,10 @@ the values of parameters.  See the GLOBAL PARAMETERS section for more details.
     uid/gid preservation requires the module to be running as root (see "uid")
     or for "fake super" to be configured.
 
-    A chroot-enabled module should not have this parameter enabled unless
-    you've taken steps to ensure that the module has the necessary resources it
-    needs to translate names, and that it is not possible for a user to change
-    those resources.  That includes being the code being able to call functions
-    like **getpwuid()**, **getgrgid()**, **getpwname()**, and **getgrnam()**.
-    You should test what libraries and config files are required for your OS
-    and get those setup before starting to test name mapping in rsync.
+    A chroot-enabled module should not have this parameter set to false unless
+    you're using a "name converter" program *or* you've taken steps to ensure
+    that the module has the necessary resources it needs to translate names and
+    that it is not possible for a user to change those resources.
 
 0.  `munge symlinks`
 
diff --git a/support/nameconvert b/support/nameconvert
new file mode 100755
index 00000000..968fdbe3
--- /dev/null
+++ b/support/nameconvert
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+
+# This implements a simple protocol to do user & group conversions between
+# names & ids.  All input and output consists of simple strings with a
+# terminating newline.
+#
+# The requests can be:
+#
+#   uid ID_NUM\n  ->  NAME\n
+#   gid ID_NUM\n  ->  NAME\n
+#   usr NAME\n    ->  ID_NUM\n
+#   grp NAME\n    ->  ID_NUM\n
+#
+# An unknown ID_NUM or NAME results in an empty return value.
+#
+# This is used by an rsync daemon when configured with the "name converter" and
+# "use chroot = true".  While this converter uses real user & group lookups you
+# could change it to use any mapping idiom you'd like.
+
+import sys, argparse, pwd, grp
+
+def main():
+    for line in sys.stdin:
+        try:
+            req, arg = line.rstrip().split(' ', 1)
+        except:
+            req = None
+        try:
+            if req == 'uid':
+                ans = pwd.getpwuid(int(arg)).pw_name
+            elif req == 'gid':
+                ans = grp.getgrgid(int(arg)).gr_name
+            elif req == 'usr':
+                ans = pwd.getpwnam(arg).pw_uid
+            elif req == 'grp':
+                ans = grp.getgrnam(arg).gr_gid
+            else:
+                print("Invalid request", file=sys.stderr)
+                sys.exit(1)
+        except KeyError:
+            ans = ''
+        print(ans, flush=True)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description="Convert users & groups between names & numbers for an rsync daemon.")
+    args = parser.parse_args()
+    main()
+
+# vim: sw=4 et
diff --git a/uidlist.c b/uidlist.c
index 4506de2e..88847424 100644
--- a/uidlist.c
+++ b/uidlist.c
@@ -34,6 +34,7 @@ extern int preserve_gid;
 extern int preserve_acls;
 extern int numeric_ids;
 extern int xmit_id0_names;
+extern pid_t namecvt_pid;
 extern gid_t our_gid;
 extern char *usermap;
 extern char *groupmap;
@@ -98,50 +99,86 @@ static struct idlist *add_to_list(struct idlist **root, id_t id, union name_or_i
 /* turn a uid into a user name */
 const char *uid_to_user(uid_t uid)
 {
-	struct passwd *pass = getpwuid(uid);
-	if (pass)
-		return strdup(pass->pw_name);
-	return NULL;
+	const char *name = NULL;
+
+	if (namecvt_pid) {
+		id_t id = uid;
+		namecvt_call("uid", &name, &id);
+	} else {
+		struct passwd *pass = getpwuid(uid);
+		if (pass)
+			name = strdup(pass->pw_name);
+	}
+
+	return name;
 }
 
 /* turn a gid into a group name */
 const char *gid_to_group(gid_t gid)
 {
-	struct group *grp = getgrgid(gid);
-	if (grp)
-		return strdup(grp->gr_name);
-	return NULL;
+	const char *name = NULL;
+
+	if (namecvt_pid) {
+		id_t id = gid;
+		namecvt_call("gid", &name, &id);
+	} else {
+		struct group *grp = getgrgid(gid);
+		if (grp)
+			name = strdup(grp->gr_name);
+	}
+
+	return name;
 }
 
 /* Parse a user name or (optionally) a number into a uid */
 int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok)
 {
-	struct passwd *pass;
 	if (!name || !*name)
 		return 0;
+
 	if (num_ok && name[strspn(name, "0123456789")] == '\0') {
 		*uid_p = id_parse(name);
 		return 1;
 	}
-	if (!(pass = getpwnam(name)))
-		return 0;
-	*uid_p = pass->pw_uid;
+
+	if (namecvt_pid) {
+		id_t id;
+		if (!namecvt_call("usr", &name, &id))
+			return 0;
+		*uid_p = id;
+	} else {
+		struct passwd *pass = getpwnam(name);
+		if (!pass)
+			return 0;
+		*uid_p = pass->pw_uid;
+	}
+
 	return 1;
 }
 
 /* Parse a group name or (optionally) a number into a gid */
 int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok)
 {
-	struct group *grp;
 	if (!name || !*name)
 		return 0;
+
 	if (num_ok && name[strspn(name, "0123456789")] == '\0') {
 		*gid_p = id_parse(name);
 		return 1;
 	}
-	if (!(grp = getgrnam(name)))
-		return 0;
-	*gid_p = grp->gr_gid;
+
+	if (namecvt_pid) {
+		id_t id;
+		if (!namecvt_call("grp", &name, &id))
+			return 0;
+		*gid_p = id;
+	} else {
+		struct group *grp = getgrnam(name);
+		if (!grp)
+			return 0;
+		*gid_p = grp->gr_gid;
+	}
+
 	return 1;
 }
 


-- 
The rsync repository.



More information about the rsync-cvs mailing list