Promoted nameconverter to master (with changes).
authorWayne Davison <wayne@opencoder.net>
Fri, 17 Jul 2020 17:48:47 +0000 (10:48 -0700)
committerWayne Davison <wayne@opencoder.net>
Fri, 17 Jul 2020 17:48:47 +0000 (10:48 -0700)
nameconverter.diff [deleted file]

diff --git a/nameconverter.diff b/nameconverter.diff
deleted file mode 100644 (file)
index 4e7e1bb..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-This patch adds a "name converter" daemon option that allows you
-to specify a user-/group- name converter program that converts
-between ID numbers and names.  This only works in daemon mode,
-and is useful for both chroot use (since the converter runs
-outside the chroot) or to specify a converter that doesn't use
-the normal passwd/group setup.
-
-The converter must use a null char ('\0') as the line terminator
-for input/output on stdin/stdout.  A sample converter written in
-perl is supplied in the support dir: nameconvert.  To use it,
-specify this daemon option:
-
-    name converter = /path/nameconvert
-
-If /path/ is omitted, the script will be found on the $PATH.
-
-To use this patch, run these commands for a successful build:
-
-    patch -p1 <patches/nameconverter.diff
-    ./configure                         (optional if already run)
-    make
-
-based-on: bb16db1747e1119e3cbdbcee6d47ecd68def66cc
-diff --git a/clientserver.c b/clientserver.c
---- 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;
-@@ -811,7 +814,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 +877,45 @@ 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)) {
-+                      int fds_to[2], fds_from[2];
-+                      if (pipe(fds_to) < 0 || pipe(fds_from) < 0
-+                       || (namecvt_pid = fork()) < 0) {
-+                              rsyserr(FLOG, errno, "name-converter exec preparation failed");
-+                              io_printf(f_out, "@ERROR: name-converter exec preparation failed\n");
-+                              return -1;
-+                      }
-+                      if (namecvt_pid == 0) {
-+                              char *args[100], *run = lp_name_converter(module_id);
-+                              int cnt = 0;
-+                              close(fds_to[1]);
-+                              close(fds_from[0]);
-+                              set_blocking(fds_to[0]);
-+                              set_blocking(fds_from[1]);
-+                              close(STDIN_FILENO);
-+                              close(STDOUT_FILENO);
-+                              dup2(fds_to[0], STDIN_FILENO);
-+                              dup2(fds_from[1], STDOUT_FILENO);
-+                              while (cnt+1 < (int)(sizeof args / sizeof (char *))) {
-+                                      char *space = strchr(run, ' ');
-+                                      args[cnt++] = run;
-+                                      if (!space)
-+                                              break;
-+                                      *space = '\0';
-+                                      run = space + 1;
-+                              }
-+                              args[cnt] = NULL;
-+                              execvp(args[0], args);
-+                              _exit(1);
-+                      }
-+                      close(fds_to[0]);
-+                      close(fds_from[1]);
-+                      set_blocking(fds_to[1]);
-+                      set_blocking(fds_from[0]);
-+                      namecvt_fd_req = fds_to[1];
-+                      namecvt_fd_ans = fds_from[0];
-+              }
-       }
- #endif
-@@ -1124,6 +1167,44 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
-       return 0;
- }
-+int namecvt_name(const char *cmd, const char *name)
-+{
-+      char buf[1024];
-+      int got, len = snprintf(buf, sizeof buf, "%s %s", cmd, name);
-+      if (len >= (int)sizeof buf) {
-+              rprintf(FERROR, "namecvt_name() request was too large.\n");
-+              exit_cleanup(RERR_UNSUPPORTED);
-+      }
-+      while ((got = write(namecvt_fd_req, buf, len + 1)) != len + 1) {
-+              if (got < 0 && errno == EINTR)
-+                      continue;
-+              rprintf(FERROR, "Connection to name-converter failed.\n");
-+              exit_cleanup(RERR_SOCKETIO);
-+      }
-+      if (!(len = read_arg_from_pipe(namecvt_fd_ans, buf, sizeof buf)))
-+              return 0;
-+      return atoi(buf);
-+}
-+
-+const char *namecvt_id(const char *cmd, int id)
-+{
-+      char buf[1024];
-+      int got, len = snprintf(buf, sizeof buf, "%s %d", cmd, id);
-+      if (len >= (int)sizeof buf) {
-+              rprintf(FERROR, "namecvt_id() request was too large.\n");
-+              exit_cleanup(RERR_UNSUPPORTED);
-+      }
-+      while ((got = write(namecvt_fd_req, buf, len + 1)) != len + 1) {
-+              if (got < 0 && errno == EINTR)
-+                      continue;
-+              rprintf(FERROR, "Connection to name-converter failed.\n");
-+              exit_cleanup(RERR_SOCKETIO);
-+      }
-+      if (!(len = read_arg_from_pipe(namecvt_fd_ans, buf, sizeof buf)))
-+              return NULL;
-+      return strdup(buf);
-+}
-+
- /* 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
---- 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
---- a/rsyncd.conf.5.md
-+++ b/rsyncd.conf.5.md
-@@ -316,6 +316,29 @@ the values of parameters.  See the GLOBAL PARAMETERS section for more details.
-     There are tricky ways to work around this, though, so you had better trust
-     your users if you choose this combination of parameters.
-+0.  `name converter`
-+
-+    This parameter lets you specify a program that will be run by the rsync
-+    daemon (prior to `use chroot`, if that parameter is enabled) to convert
-+    user/group names into numbers or visa versa.  There is a sample perl script
-+    in the support directory named "nameconvert" that you can use to enable the
-+    use of the normal passwd/group lookup calls in a chroot daemon (which does
-+    not require any extra files be placed in the chroot area).  This use is
-+    configured as follows:
-+
-+    >     name converter = /path/nameconvert)
-+
-+    You could alternately specify a program that responds to each request using
-+    a lookup table to find the names and numbers, this allows you to configure
-+    per-module name conversion.  See the support/nameconvert script for the
-+    details of what requests can be sent to the program.
-+
-+    The program will have access to some of the environment variables that are
-+    described in the section on `pre-xfer exec`: `RSYNC_MODULE_NAME`,
-+    `RSYNC_MODULE_PATH`, `RSYNC_HOST_ADDR`, `RSYNC_HOST_NAME`, and
-+    `RSYNC_USER_NAME`.  This is useful if you want to customize the conversion
-+    using a single program invocation.
-+
- 0.  `charset`
-     This specifies the name of the character set in which the module's
-diff --git a/support/nameconvert b/support/nameconvert
-new file mode 100755
---- /dev/null
-+++ b/support/nameconvert
-@@ -0,0 +1,42 @@
-+#!/usr/bin/perl -w
-+# This implements a simple protocol to do {user,group}-{name,id}
-+# conversions.  All input and output consists of simple strings
-+# with a terminating null char (or newline for debugging).  If
-+# the conversion fails, an empty string is returned.
-+#
-+# The requests can be:
-+#
-+# uid ID_NUM\0  ->  NAME\0
-+# gid ID_NUM\0  ->  NAME\0
-+# usr NAME\0    ->  ID_NUM\0
-+# grp NAME\0    ->  ID_NUM\0
-+#
-+# 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" setting.
-+
-+use strict;
-+
-+my $eol = grep(/^--debug$/, @ARGV) ? "\n" : "\0";
-+$/ = $eol;
-+
-+$| = 1;
-+
-+while (<STDIN>) {
-+    chomp;
-+    my $ans;
-+    if (/^uid (\d+)$/) {
-+      $ans = getpwuid($1);
-+    } elsif (/^gid (\d+)$/) {
-+      $ans = getgrgid($1);
-+    } elsif (/^usr (\S+)$/) {
-+      $ans = getpwnam($1);
-+    } elsif (/^grp (\S+)$/) {
-+      $ans = getgrnam($1);
-+    } else {
-+      die "Invalid request: $_";
-+    }
-+    $ans = '' unless defined $ans;
-+    print $ans, $eol;
-+}
-diff --git a/t_stub.c b/t_stub.c
---- a/t_stub.c
-+++ b/t_stub.c
-@@ -36,6 +36,7 @@ int open_noatime = 0;
- size_t max_alloc = 1024*1024*1024; /* max_alloc is needed when combined with util2.o */
- char *partial_dir;
- char *module_dir;
-+pid_t namecvt_pid;
- filter_rule_list daemon_filter_list;
-  void rprintf(UNUSED(enum logcode code), const char *format, ...)
-@@ -86,6 +87,11 @@ filter_rule_list daemon_filter_list;
-       return;
- }
-+ int namecvt_name(UNUSED(const char *cmd), UNUSED(const char *name))
-+{
-+      return 0;
-+}
-+
-  char *lp_name(UNUSED(int mod))
- {
-       return NULL;
-diff --git a/uidlist.c b/uidlist.c
---- 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,8 +99,12 @@ 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)
-+      struct passwd *pass;
-+
-+      if (namecvt_pid)
-+              return namecvt_id("uid", (int)uid);
-+
-+      if ((pass = getpwuid(uid)) != NULL)
-               return strdup(pass->pw_name);
-       return NULL;
- }
-@@ -107,8 +112,12 @@ const char *uid_to_user(uid_t uid)
- /* turn a gid into a group name */
- const char *gid_to_group(gid_t gid)
- {
--      struct group *grp = getgrgid(gid);
--      if (grp)
-+      struct group *grp;
-+
-+      if (namecvt_pid)
-+              return namecvt_id("gid", (int)gid);
-+
-+      if ((grp = getgrgid(gid)) != NULL)
-               return strdup(grp->gr_name);
-       return NULL;
- }
-@@ -116,32 +125,54 @@ const char *gid_to_group(gid_t gid)
- /* 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;
-+      uid_t uid;
-+
-       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) {
-+              if (!(uid = namecvt_name("usr", name)))
-+                      return 0;
-+      } else {
-+              struct passwd *pass;
-+              if (!(pass = getpwnam(name)))
-+                      return 0;
-+              uid = pass->pw_uid;
-+      }
-+
-+      *uid_p = 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;
-+      gid_t gid;
-+
-       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) {
-+              if (!(gid = namecvt_name("grp", name)))
-+                      return 0;
-+      } else {
-+              struct group *grp;
-+              if (!(grp = getgrnam(name)))
-+                      return 0;
-+              gid = grp->gr_gid;
-+      }
-+
-+      *gid_p = gid;
-       return 1;
- }
-diff --git a/util.c b/util.c
---- a/util.c
-+++ b/util.c
-@@ -36,6 +36,8 @@ extern int preallocate_files;
- extern char *module_dir;
- extern unsigned int module_dirlen;
- extern char *partial_dir;
-+extern pid_t namecvt_pid;
-+extern unsigned int module_dirlen;
- extern filter_rule_list daemon_filter_list;
- int sanitize_paths = 0;