[Pkg-sssd-devel] sssd: Changes to 'ubuntu-precise'

Timo Aaltonen tjaalton-guest at alioth.debian.org
Tue Feb 5 23:35:47 UTC 2013


 Makefile.am                            |    7 
 configure.ac                           |    4 
 debian/changelog                       |   16 
 debian/rules                           |    3 
 src/monitor/monitor.c                  |   73 ++
 src/providers/ipa/ipa_init.c           |   13 
 src/providers/krb5/krb5_auth.c         |    3 
 src/providers/ldap/sdap.c              |    8 
 src/providers/ldap/sdap_async_groups.c |   24 
 src/responder/autofs/autofssrv_cmd.c   |    6 
 src/responder/common/responder_cmd.c   |    2 
 src/responder/common/responder_dp.c    |   34 +
 src/responder/nss/nsssrv_netgroup.c    |    2 
 src/responder/nss/nsssrv_services.c    |    2 
 src/responder/pam/pamsrv.c             |    5 
 src/responder/pam/pamsrv_cmd.c         |   29 -
 src/responder/ssh/sshsrv_cmd.c         |    8 
 src/tests/files-tests.c                |    6 
 src/tools/files.c                      |  913 ++++++++++++++++++---------------
 src/tools/tools_util.c                 |   28 -
 src/tools/tools_util.h                 |    5 
 src/util/auth_utils.h                  |   42 +
 version.m4                             |    2 
 23 files changed, 761 insertions(+), 474 deletions(-)

New commits:
commit ee73860103fb16a2473cb7a26a599ceaca56c3d0
Author: Timo Aaltonen <tjaalton at ubuntu.com>
Date:   Wed Feb 6 01:09:30 2013 +0200

    release to precise-proposed

diff --git a/debian/changelog b/debian/changelog
index 3b3997e..d830048 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+sssd (1.8.6-0ubuntu0.2) precise-proposed; urgency=low
+
+  * rules: Really install the new pam-auth-update file for password
+    changes. (LP: #1086272)
+  * rules: Pass --datadir, so the path in autogenerated python files is
+    correctly substituted. (LP: #1079938)
+
+ -- Timo Aaltonen <tjaalton at ubuntu.com>  Wed, 06 Feb 2013 01:07:09 +0200
+
 sssd (1.8.6-0ubuntu0.1) precise-proposed; urgency=low
 
   * New upstream bugfix release from the Long Term Maintenance branch.

commit 0bf7c82b557e07d4a3ecd06c88abc87b4a9df88c
Author: Timo Aaltonen <tjaalton at ubuntu.com>
Date:   Wed Feb 6 00:42:13 2013 +0200

    rules: Pass --datadir, so the path in autogenerated python files is correctly substituted. (LP: #1079938)
    
    Conflicts:
    	debian/changelog
    	debian/rules

diff --git a/debian/rules b/debian/rules
index fb00d79..db31657 100755
--- a/debian/rules
+++ b/debian/rules
@@ -13,6 +13,7 @@ endif
 override_dh_auto_configure:
 	dh_auto_configure -- --enable-krb5-locator-plugin \
 	--libdir=/usr/lib/$(DEB_HOST_MULTIARCH) \
+	--datadir=/usr/share/ \
 	--with-ldb-lib-dir=/usr/lib/$(DEB_HOST_MULTIARCH)/ldb/modules/ldb \
 	--with-krb5-plugin-path=/usr/lib/$(DEB_HOST_MULTIARCH)/krb5/plugins/libkrb5 \
 	--enable-nsslibdir=/lib/$(DEB_HOST_MULTIARCH) \

commit d3fd5956d94d30a4a0e9693e3247324a49f6ac38
Author: Timo Aaltonen <tjaalton at ubuntu.com>
Date:   Wed Feb 6 00:27:09 2013 +0200

    really install sss-password
    
    Conflicts:
    	debian/rules

diff --git a/debian/rules b/debian/rules
index 6d36932..fb00d79 100755
--- a/debian/rules
+++ b/debian/rules
@@ -31,6 +31,8 @@ override_dh_install:
 	mkdir -p $(CURDIR)/debian/libpam-sss/usr/share/pam-configs
 	install -m644 debian/libpam-sss.pam-auth-update \
 		$(CURDIR)/debian/libpam-sss/usr/share/pam-configs/sss
+	install -m644 debian/libpam-sss.pam-auth-update-password \
+		$(CURDIR)/debian/libpam-sss/usr/share/pam-configs/sss-password
 
 	cat $(CURDIR)/debian/sssd.$(INIT).in > $(CURDIR)/debian/sssd.$(INIT)
 

commit 9c304de5a28b5541191dff721d6d6c7b35a2eb85
Author: Timo Aaltonen <tjaalton at ubuntu.com>
Date:   Wed Jan 30 10:20:07 2013 +0200

    update the changelog

diff --git a/debian/changelog b/debian/changelog
index 6e86e3b..3b3997e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-sssd (1.8.5-0ubuntu0.1) precise-proposed; urgency=low
+sssd (1.8.6-0ubuntu0.1) precise-proposed; urgency=low
 
   * New upstream bugfix release from the Long Term Maintenance branch.
     (LP: #1086304)
@@ -8,6 +8,9 @@ sssd (1.8.5-0ubuntu0.1) precise-proposed; urgency=low
       nested structure (LP: #981125)
     - Don't corrupt the credential cache when canonizing principals
       (LP: #985031)
+    - Fix race conditions when creating or removing home directories for
+      users in local domain. (LP: #1105893)
+    - Fix out-of-bounds reads in autofs and ssh responder. (LP: #1105898)
   * sssd.upstart.in: Delete an invisible control character from the pre-start
     script. (LP: #1003845)
   * Replace perl snippet from libnss-sss.post* with sed, drop perl from
@@ -20,7 +23,7 @@ sssd (1.8.5-0ubuntu0.1) precise-proposed; urgency=low
   * rules: Drop remnants of cdbs, use proper paths for configure.
     (LP: #1079938)
 
- -- Timo Aaltonen <tjaalton at ubuntu.com>  Tue, 04 Dec 2012 11:47:05 +0200
+ -- Timo Aaltonen <tjaalton at ubuntu.com>  Wed, 30 Jan 2013 10:47:46 +0200
 
 sssd (1.8.2-0ubuntu1) precise; urgency=low
 

commit ddf821a5589218dc46a14d3ebf8b845e14db898d
Author: Jakub Hrozek <jhrozek at redhat.com>
Date:   Tue Jan 29 16:49:26 2013 +0100

    Include the auth_utils.h header in the distribution

diff --git a/Makefile.am b/Makefile.am
index 01a1abb..90c850b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -328,6 +328,7 @@ dist_noinst_HEADERS = \
     src/util/find_uid.h \
     src/util/user_info_msg.h \
     src/util/murmurhash3.h \
+    src/util/auth_utils.h \
     src/monitor/monitor.h \
     src/monitor/monitor_interfaces.h \
     src/responder/common/responder.h \

commit 9d096f42802208d6cb54ab25a2e9cc90925f84c7
Author: Jakub Hrozek <jhrozek at redhat.com>
Date:   Fri Jan 25 10:57:54 2013 -0500

    TOOLS: Compile on old platforms such as RHEL5
    
    Provides compatible declarations for modern file management functions
    such as futimens or opening with the O_CLOEXEC flag

diff --git a/configure.ac b/configure.ac
index 2cde251..9245ae7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,6 +63,10 @@ AC_CHECK_FUNCS([ pthread_mutexattr_setrobust \
                  pthread_mutex_consistent_np ])
 LIBS=$SAVE_LIBS
 
+# Check for presence of modern functions for setting file timestamps
+AC_CHECK_FUNCS([ utimensat \
+                 futimens ])
+
 #Check for PAM headers
 AC_CHECK_HEADERS([security/pam_appl.h security/pam_misc.h security/pam_modules.h],
     [AC_CHECK_LIB(pam, pam_get_item, [ PAM_LIBS="-lpam" ], [AC_MSG_ERROR([PAM must support pam_get_item])])],
diff --git a/src/tools/files.c b/src/tools/files.c
index 3d2273f..a3bc517 100644
--- a/src/tools/files.c
+++ b/src/tools/files.c
@@ -54,6 +54,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
+
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -62,7 +64,6 @@
 #include <errno.h>
 #include <talloc.h>
 
-#include "config.h"
 #include "util/util.h"
 #include "tools/tools_util.h"
 
@@ -74,6 +75,125 @@ struct copy_ctx {
     gid_t       gid;
 };
 
+static int open_cloexec(const char *pathname, int flags, int *ret)
+{
+    int fd;
+    int oflags;
+
+    oflags = flags;
+#ifdef O_CLOEXEC
+    oflags |= O_CLOEXEC;
+#endif
+
+    errno = 0;
+    fd = open(pathname, oflags);
+    if (fd == -1) {
+        if (ret) {
+            *ret = errno;
+        }
+        return -1;
+    }
+
+#ifndef O_CLOEXEC
+    int v;
+
+    v = fcntl(fd, F_GETFD, 0);
+    /* we ignore an error, it's not fatal and there is nothing we
+     * can do about it anyways */
+    (void)fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+#endif
+
+    return fd;
+}
+
+static int openat_cloexec(int dir_fd, const char *pathname, int flags, int *ret)
+{
+    int fd;
+    int oflags;
+
+    oflags = flags;
+#ifdef O_CLOEXEC
+    oflags |= O_CLOEXEC;
+#endif
+
+    errno = 0;
+    fd = openat(dir_fd, pathname, oflags);
+    if (fd == -1) {
+        if (ret) {
+            *ret = errno;
+        }
+        return -1;
+    }
+
+#ifndef O_CLOEXEC
+    int v;
+
+    v = fcntl(fd, F_GETFD, 0);
+    /* we ignore an error, it's not fatal and there is nothing we
+     * can do about it anyways */
+    (void)fcntl(fd, F_SETFD, v | FD_CLOEXEC);
+#endif
+
+    return fd;
+}
+
+static int sss_timeat_set(int dir_fd, const char *path,
+                          const struct stat *statp,
+                          int flags)
+{
+    int ret;
+
+#ifdef HAVE_UTIMENSAT
+    struct timespec timebuf[2];
+
+    timebuf[0] = statp->st_atim;
+    timebuf[1] = statp->st_mtim;
+
+    ret = utimensat(dir_fd, path, timebuf, flags);
+#else
+    struct timeval tv[2];
+
+    tv[0].tv_sec  = statp->st_atime;
+    tv[0].tv_usec = 0;
+    tv[1].tv_sec = statp->st_mtime;
+    tv[1].tv_usec = 0;
+
+    ret = futimesat(dir_fd, path, tv);
+#endif
+    if (ret == -1) {
+        return errno;
+    }
+
+    return EOK;
+}
+
+static int sss_futime_set(int fd, const struct stat *statp)
+{
+    int ret;
+
+#ifdef HAVE_FUTIMENS
+    struct timespec timebuf[2];
+
+    timebuf[0] = statp->st_atim;
+    timebuf[1] = statp->st_mtim;
+    ret = futimens(fd, timebuf);
+#else
+    struct timeval tv[2];
+
+    tv[0].tv_sec  = statp->st_atime;
+    tv[0].tv_usec = 0;
+    tv[1].tv_sec = statp->st_mtime;
+    tv[1].tv_usec = 0;
+
+    ret = futimes(fd, tv);
+#endif
+    if (ret == -1) {
+        return errno;
+    }
+
+    return EOK;
+}
+
 /* wrapper in order not to create a temporary context in
  * every iteration */
 static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx,
@@ -112,8 +232,8 @@ static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx,
     int ret, err;
     int dir_fd;
 
-    dir_fd = openat(parent_fd, dir_name,
-                    O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW);
+    dir_fd = openat_cloexec(parent_fd, dir_name,
+                            O_RDONLY | O_DIRECTORY | O_NOFOLLOW, &ret);
     if (dir_fd == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot open %s: [%d]: %s\n",
@@ -246,7 +366,6 @@ copy_symlink(int src_dir_fd,
 {
     char *buf;
     errno_t ret;
-    struct timespec timebuf[2];
 
     buf = talloc_readlinkat(NULL, src_dir_fd, file_name);
     if (!buf) {
@@ -283,12 +402,9 @@ copy_symlink(int src_dir_fd,
         return ret;
     }
 
-    timebuf[0] = statp->st_atim;
-    timebuf[1] = statp->st_mtim;
-    ret = utimensat(dst_dir_fd, file_name, timebuf,
-                    AT_SYMLINK_NOFOLLOW);
-    if (ret == -1) {
-        ret = errno;
+    ret = sss_timeat_set(dst_dir_fd, file_name, statp,
+                         AT_SYMLINK_NOFOLLOW);
+    if (ret != EOK) {
         DEBUG(SSSDBG_MINOR_FAILURE, ("utimensat failed [%d]: %s\n",
               ret, strerror(ret)));
         /* Do not fail */
@@ -309,7 +425,6 @@ static int copy_special(int dst_dir_fd,
                         uid_t uid, gid_t gid)
 {
     int ret;
-    struct timespec timebuf[2];
 
     ret = selinux_file_context(full_path);
     if (ret != 0) {
@@ -346,9 +461,7 @@ static int copy_special(int dst_dir_fd,
         return ret;
     }
 
-    timebuf[0] = statp->st_atim;
-    timebuf[1] = statp->st_mtim;
-    ret = utimensat(dst_dir_fd, file_name, timebuf, 0);
+    ret = sss_timeat_set(dst_dir_fd, file_name, statp, 0);
     if (ret == -1) {
         ret = errno;
         DEBUG(SSSDBG_MINOR_FAILURE,
@@ -376,7 +489,6 @@ copy_file(int ifd,
     errno_t ret;
     char buf[1024];
     ssize_t cnt, written;
-    struct timespec timebuf[2];
 
     ret = selinux_file_context(full_path);
     if (ret != 0) {
@@ -443,12 +555,9 @@ copy_file(int ifd,
               goto done;
     }
 
-    timebuf[0] = statp->st_atim;
-    timebuf[1] = statp->st_mtim;
-    ret = futimens(ofd, timebuf);
-    if (ret == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_MINOR_FAILURE, ("futimens failed [%d]: %s\n",
+    ret = sss_futime_set(ofd, statp);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("sss_futime_set failed [%d]: %s\n",
               ret, strerror(ret)));
         /* Do not fail */
     }
@@ -498,15 +607,14 @@ copy_entry(struct copy_ctx *cctx,
      * us against FIFOs and perhaps side-effects of the open() of a
      * device file if there ever was one here, and doesn't matter
      * for regular files or directories. */
-    ifd = openat(src_dir_fd, ent_name,
-                 O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK);
-    if (ifd == -1 && errno != ELOOP) {
+    ifd = openat_cloexec(src_dir_fd, ent_name,
+                         O_RDONLY | O_NOFOLLOW | O_NONBLOCK, &ret);
+    if (ifd == -1 && ret != ELOOP) {
         /* openat error */
-        ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE, ("openat failed on '%s': %s\n",
               src_ent_path, strerror(ret)));
         goto done;
-    } else if (ifd == -1 && errno == ELOOP) {
+    } else if (ifd == -1 && ret == ELOOP) {
         /* Should be a symlink.. */
         ret = fstatat(src_dir_fd, ent_name, &st, AT_SYMLINK_NOFOLLOW);
         if (ret == -1) {
@@ -586,7 +694,6 @@ copy_dir(struct copy_ctx *cctx,
     int dest_dir_fd = -1;
     DIR *dir = NULL;
     struct dirent *ent;
-    struct timespec timebuf[2];
 
     if (!dest_dir_path) {
         return EINVAL;
@@ -613,8 +720,8 @@ copy_dir(struct copy_ctx *cctx,
         goto done;
     }
 
-    dest_dir_fd = openat(dest_parent_fd, dest_dir_name,
-                         O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW);
+    dest_dir_fd = openat_cloexec(dest_parent_fd, dest_dir_name,
+                                 O_RDONLY | O_DIRECTORY | O_NOFOLLOW, &ret);
     if (dest_dir_fd == -1) {
         ret = errno;
         DEBUG(SSSDBG_CRIT_FAILURE,
@@ -663,12 +770,9 @@ copy_dir(struct copy_ctx *cctx,
         goto done;
     }
 
-    timebuf[0] = src_dir_stat->st_atim;
-    timebuf[1] = src_dir_stat->st_mtim;
-    futimens(dest_dir_fd, timebuf);
-    if (ret == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_MINOR_FAILURE, ("futimens failed [%d]: %s\n",
+    sss_futime_set(dest_dir_fd, src_dir_stat);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("sss_futime_set failed [%d]: %s\n",
               ret, strerror(ret)));
         /* Do not fail */
     }
@@ -695,9 +799,8 @@ int copy_tree(const char *src_root, const char *dst_root,
     int fd = -1;
     struct stat s_src;
 
-    fd = open(src_root, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
+    fd = open_cloexec(src_root, O_RDONLY | O_DIRECTORY, &ret);
     if (fd == -1) {
-        ret = errno;
         goto fail;
     }
 

commit cfcfa9bd014a7717821c98262a11772c8e79c13e
Author: Ondrej Kos <okos at redhat.com>
Date:   Tue Jan 29 14:15:48 2013 +0100

    TOOLS: Use file descriptor to avoid races when creating a home directory
    
    When creating a home directory, the destination tree can be modified in
    various ways while it is being constructed because directory
    permissions
    are set before populating the directory. This can lead to file creation
    and permission changes outside the target directory tree, using hard
    links.
    
    This security problem was assigned CVE-2013-0219
    
    https://fedorahosted.org/sssd/ticket/1782

diff --git a/Makefile.am b/Makefile.am
index e64cc09..01a1abb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -755,6 +755,7 @@ FILES_TESTS_LIBS = \
     $(CHECK_LIBS) \
     $(POPT_LIBS) \
     $(TALLOC_LIBS) \
+	$(DHASH_LIBS) \
     libsss_test_common.la
 if BUILD_SELINUX
     FILES_TESTS_LIBS += $(SELINUX_LIBS)
@@ -767,7 +768,8 @@ files_tests_SOURCES = \
     src/tests/files-tests.c \
     src/util/check_and_open.c \
     src/tools/selinux.c \
-    src/tools/files.c
+    src/tools/files.c \
+	src/util/util.c
 files_tests_CFLAGS = \
     $(AM_CFLAGS) \
     $(CHECK_CFLAGS)
diff --git a/src/tests/files-tests.c b/src/tests/files-tests.c
index cb20e1a..06aa596 100644
--- a/src/tests/files-tests.c
+++ b/src/tests/files-tests.c
@@ -183,7 +183,7 @@ START_TEST(test_simple_copy)
 
     /* and finally copy.. */
     DEBUG(5, ("Will copy from '%s' to '%s'\n", dir_path, dst_path));
-    ret = copy_tree(dir_path, dst_path, uid, gid);
+    ret = copy_tree(dir_path, dst_path, 0700, uid, gid);
     fail_unless(ret == EOK, "copy_tree failed\n");
 
     /* check if really copied */
@@ -225,7 +225,7 @@ START_TEST(test_copy_symlink)
 
     /* and finally copy.. */
     DEBUG(5, ("Will copy from '%s' to '%s'\n", dir_path, dst_path));
-    ret = copy_tree(dir_path, dst_path, uid, gid);
+    ret = copy_tree(dir_path, dst_path, 0700, uid, gid);
     fail_unless(ret == EOK, "copy_tree failed\n");
 
     /* check if really copied */
@@ -264,7 +264,7 @@ START_TEST(test_copy_node)
 
     /* and finally copy.. */
     DEBUG(5, ("Will copy from '%s' to '%s'\n", dir_path, dst_path));
-    ret = copy_tree(dir_path, dst_path, uid, gid);
+    ret = copy_tree(dir_path, dst_path, 0700, uid, gid);
     fail_unless(ret == EOK, "copy_tree failed\n");
 
     /* check if really copied */
diff --git a/src/tools/files.c b/src/tools/files.c
index ad6f1c0..3d2273f 100644
--- a/src/tools/files.c
+++ b/src/tools/files.c
@@ -66,13 +66,12 @@
 #include "util/util.h"
 #include "tools/tools_util.h"
 
-int copy_tree(const char *src_root, const char *dst_root,
-              uid_t uid, gid_t gid);
-
 struct copy_ctx {
     const char *src_orig;
     const char *dst_orig;
     dev_t       src_dev;
+    uid_t       uid;
+    gid_t       gid;
 };
 
 /* wrapper in order not to create a temporary context in
@@ -197,66 +196,13 @@ fail:
     return ret;
 }
 
-static int copy_dir(const char *src, const char *dst,
-                    const struct stat *statp, const struct timeval mt[2],
-                    uid_t uid, gid_t gid)
-{
-    int ret = 0;
-
-    /*
-     * Create a new target directory, make it owned by
-     * the user and then recursively copy that directory.
-     */
-    selinux_file_context(dst);
-
-    ret = mkdir(dst, statp->st_mode);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot mkdir directory '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        return ret;
-    }
-
-    ret = chown(dst, uid, gid);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot chown directory '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        return ret;
-    }
-
-    ret = chmod(dst, statp->st_mode);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot chmod directory '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        return ret;
-    }
-
-    ret = copy_tree(src, dst, uid, gid);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot copy directory from '%s' to '%s': [%d][%s].\n",
-                  src, dst, ret, strerror(ret)));
-        return ret;
-    }
-
-    ret = utimes(dst, mt);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot set utimes on a directory '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        return ret;
-    }
-
-    return EOK;
-}
-
-static char *talloc_readlink(TALLOC_CTX *mem_ctx, const char *filename)
+static char *talloc_readlinkat(TALLOC_CTX *mem_ctx, int dir_fd,
+                               const char *filename)
 {
     size_t size = 1024;
     ssize_t nchars;
     char *buffer;
+    char *new_buffer;
 
     buffer = talloc_array(mem_ctx, char, size);
     if (!buffer) {
@@ -264,8 +210,9 @@ static char *talloc_readlink(TALLOC_CTX *mem_ctx, const char *filename)
     }
 
     while (1) {
-        nchars = readlink(filename, buffer, size);
+        nchars = readlinkat(dir_fd, filename, buffer, size);
         if (nchars < 0) {
+            talloc_free(buffer);
             return NULL;
         }
 
@@ -276,10 +223,12 @@ static char *talloc_readlink(TALLOC_CTX *mem_ctx, const char *filename)
 
         /* Try again with a bigger buffer */
         size *= 2;
-        buffer = talloc_realloc(mem_ctx, buffer, char, size);
-        if (!buffer) {
+        new_buffer = talloc_realloc(mem_ctx, buffer, char, size);
+        if (!new_buffer) {
+            talloc_free(buffer);
             return NULL;
         }
+        buffer = new_buffer;
     }
 
     /* readlink does not nul-terminate */
@@ -287,424 +236,500 @@ static char *talloc_readlink(TALLOC_CTX *mem_ctx, const char *filename)
     return buffer;
 }
 
-static int copy_symlink(struct copy_ctx *cctx,
-                        const char *src,
-                        const char *dst,
-                        const struct stat *statp,
-                        const struct timeval mt[],
-                        uid_t uid, gid_t gid)
+static int
+copy_symlink(int src_dir_fd,
+             int dst_dir_fd,
+             const char *file_name,
+             const char *full_path,
+             const struct stat *statp,
+             uid_t uid, gid_t gid)
 {
-    int ret;
-    char *oldlink;
-    char *tmp;
-    TALLOC_CTX *tmp_ctx = NULL;
+    char *buf;
+    errno_t ret;
+    struct timespec timebuf[2];
 
-    tmp_ctx = talloc_new(cctx);
-    if (!tmp_ctx) {
+    buf = talloc_readlinkat(NULL, src_dir_fd, file_name);
+    if (!buf) {
         return ENOMEM;
     }
 
-    /*
-     * Get the name of the file which the link points
-     * to.  If that name begins with the original
-     * source directory name, that part of the link
-     * name will be replaced with the original
-     * destination directory name.
-     */
-    oldlink = talloc_readlink(tmp_ctx, src);
-    if (oldlink == NULL) {
-        ret = ENOMEM;
-        goto done;
+    ret = selinux_file_context(full_path);
+    if (ret != 0) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Failed to set SELinux context for [%s]\n", full_path));
+        /* Not fatal */
     }
 
-    /* If src was a link to an entry of the src_orig directory itself,
-     * create a link to the corresponding entry in the dst_orig
-     * directory.
-     * FIXME: This may change a relative link to an absolute link
-     */
-    if (strncmp(oldlink, cctx->src_orig, strlen(cctx->src_orig)) == 0) {
-        tmp = talloc_asprintf(tmp_ctx, "%s%s", cctx->dst_orig, oldlink + strlen(cctx->src_orig));
-        if (tmp == NULL) {
-            ret = ENOMEM;
-            goto done;
+    ret = symlinkat(buf, dst_dir_fd, file_name);
+    talloc_free(buf);
+    if (ret == -1) {
+        ret = errno;
+        if (ret == EEXIST) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  ("symlink pointing to already exists at '%s'\n", full_path));
+            return EOK;
         }
 
-        talloc_free(oldlink);
-        oldlink = tmp;
+        DEBUG(SSSDBG_CRIT_FAILURE, ("symlinkat failed: %s\n", strerror(ret)));
+        return ret;
     }
 
-    selinux_file_context(dst);
-
-    ret = symlink(oldlink, dst);
-    if (ret != 0) {
+    ret = fchownat(dst_dir_fd, file_name,
+                   uid, gid, AT_SYMLINK_NOFOLLOW);
+    if (ret == -1) {
         ret = errno;
-        DEBUG(1, ("symlink() failed on file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        goto done;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+             ("fchownat failed: %s\n", strerror(ret)));
+        return ret;
     }
 
-    ret = lchown(dst, uid, gid);
-    if (ret != 0) {
+    timebuf[0] = statp->st_atim;
+    timebuf[1] = statp->st_mtim;
+    ret = utimensat(dst_dir_fd, file_name, timebuf,
+                    AT_SYMLINK_NOFOLLOW);
+    if (ret == -1) {
         ret = errno;
-        DEBUG(1, ("lchown() failed on file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        goto done;
+        DEBUG(SSSDBG_MINOR_FAILURE, ("utimensat failed [%d]: %s\n",
+              ret, strerror(ret)));
+        /* Do not fail */
     }
 
-done:
-    talloc_free(tmp_ctx);
-    return ret;
+    return EOK;
 }
 
-static int copy_special(const char *dst,
+/* Create a special file named file_name under a directory with file
+ * descriptor dst_dir_fd. full_path is used for both setting SELinux
+ * context and logging. The node is owned by uid/gid and its mode
+ * and device number is read from statp.
+ */
+static int copy_special(int dst_dir_fd,
+                        const char *file_name,
+                        const char *full_path,
                         const struct stat *statp,
-                        const struct timeval mt[],
                         uid_t uid, gid_t gid)
 {
-    int ret = 0;
+    int ret;
+    struct timespec timebuf[2];
 
-    selinux_file_context(dst);
+    ret = selinux_file_context(full_path);
+    if (ret != 0) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Failed to set SELinux context for [%s]\n", full_path));
+        /* Not fatal */
+    }
 
-    ret = mknod(dst, statp->st_mode & ~07777, statp->st_rdev);
+    ret = mknodat(dst_dir_fd, file_name, statp->st_mode & ~07777,
+                  statp->st_rdev);
     if (ret != 0) {
         ret = errno;
-        DEBUG(1, ("Cannot mknod special file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Cannot mknod special file '%s': [%d][%s].\n",
+              full_path, ret, strerror(ret)));
         return ret;
     }
 
-    ret = chown(dst, uid, gid);
+    ret = fchownat(dst_dir_fd, file_name, uid, gid, 0);
     if (ret != 0) {
         ret = errno;
-        DEBUG(1, ("Cannot chown special file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("fchownat failed for '%s': [%d][%s]\n",
+              full_path, ret, strerror(ret)));
         return ret;
     }
 
-    ret = chmod(dst, statp->st_mode & 07777);
+    ret = fchmodat(dst_dir_fd, file_name, statp->st_mode & 07777, 0);
     if (ret != 0) {
         ret = errno;
-        DEBUG(1, ("Cannot chmod special file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("fchmodat failed for '%s': [%d][%s]\n",
+              full_path, ret, strerror(ret)));
         return ret;
     }
 
-    ret = utimes(dst, mt);
-    if (ret != 0) {
+    timebuf[0] = statp->st_atim;
+    timebuf[1] = statp->st_mtim;
+    ret = utimensat(dst_dir_fd, file_name, timebuf, 0);
+    if (ret == -1) {
         ret = errno;
-        DEBUG(1, ("Cannot call utimes on special file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        return ret;
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("utimensat failed for '%s': [%d][%s]\n",
+              full_path, ret, strerror(ret)));
+        /* Do not fail, this shouldn't be fatal */
     }
 
     return EOK;
 }
 
-static int copy_file(const char *src,
-                     const char *dst,
-                     const struct stat *statp,
-                     const struct timeval mt[],
-                     uid_t uid, gid_t gid)
+/* Copy bytes from input file descriptor ifd into file named
+ * dst_named under directory with dest_dir_fd. Own the new file
+ * by uid/gid
+ */
+static int
+copy_file(int ifd,
+          int dest_dir_fd,
+          const char *file_name,
+          const char *full_path,
+          const struct stat *statp,
+          uid_t uid, gid_t gid)
 {
-    int ret;
-    int ifd = -1;
     int ofd = -1;
+    errno_t ret;
     char buf[1024];
-    ssize_t cnt, written, res;
-    struct stat fstatbuf;
-
-    ifd = open(src, O_RDONLY);
-    if (ifd < 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot open() source file '%s': [%d][%s].\n",
-                  src, ret, strerror(ret)));
-        goto fail;
-    }
+    ssize_t cnt, written;
+    struct timespec timebuf[2];
 
-    ret = fstat(ifd, &fstatbuf);
+    ret = selinux_file_context(full_path);
     if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot fstat() source file '%s': [%d][%s].\n",
-                  src, ret, strerror(ret)));
-        goto fail;
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Failed to set SELinux context for [%s]\n", full_path));
+        /* Not fatal */
     }
 
-    if (statp->st_dev != fstatbuf.st_dev ||
-        statp->st_ino != fstatbuf.st_ino) {
-        DEBUG(1, ("File %s was modified between lstat and open.\n", src));
-        ret = EIO;
-        goto fail;
-    }
-
-    selinux_file_context(dst);
-
-    ofd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
-    if (ofd < 0) {
+    /* Start with absolutely restrictive permissions */
+    ofd = openat(dest_dir_fd, file_name,
+                 O_EXCL | O_CREAT | O_WRONLY | O_NOFOLLOW,
+                 0);
+    if (ofd < 0 && errno != EEXIST) {
         ret = errno;
-        DEBUG(1, ("Cannot open() destination file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        goto fail;
-    }
-
-    ret = fchown(ofd, uid, gid);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot fchown() destination file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        goto fail;
-    }
-
-    ret = fchmod(ofd, statp->st_mode & 07777);
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(1, ("Cannot fchmod() destination file '%s': [%d][%s].\n",
-                  dst, ret, strerror(ret)));
-        goto fail;
+        DEBUG(SSSDBG_OP_FAILURE,
+               ("Cannot open() destination file '%s': [%d][%s].\n",
+               full_path, ret, strerror(ret)));
+        goto done;
     }
 
-    while ((cnt = read(ifd, buf, sizeof(buf))) != 0) {
+    while ((cnt = sss_atomic_read(ifd, buf, sizeof(buf))) != 0) {
         if (cnt == -1) {
-            if (errno == EINTR || errno == EAGAIN) {
-                continue;
-            }
-
-            DEBUG(1, ("Cannot read() from source file '%s': [%d][%s].\n",
-                        src, ret, strerror(ret)));
-            goto fail;
+            ret = errno;
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("Cannot read() from source file: [%d][%s].\n",
+                   ret, strerror(ret)));
+            goto done;
         }
-        else if (cnt > 0) {
-            /* Copy the buffer to the new file */
-            written = 0;
-            while (written < cnt) {
-                res = write(ofd, buf+written, (size_t)cnt-written);
-                if (res == -1) {
-                    ret = errno;
-                    if (ret == EINTR || ret == EAGAIN) {
-                        /* retry the write */
-                        continue;
-                    }
-                    DEBUG(1, ("Cannot write() to destination file '%s': [%d][%s].\n",
-                                dst, ret, strerror(ret)));
-                    goto fail;
-                }
-                else if (res <= 0) {
-                    DEBUG(1, ("Unexpected result from write(): [%d]\n", res));
-                    goto fail;
-                }
-
-                written += res;
-            }
+
+        errno = 0;
+        written = sss_atomic_write(ofd, buf, cnt);
+        if (written == -1) {
+            ret = errno;
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("Cannot write() to destination file: [%d][%s].\n",
+                   ret, strerror(ret)));
+            goto done;
         }
-        else {
-            DEBUG(1, ("Unexpected return code of read [%d]\n", cnt));
-            goto fail;
+
+        if (written != cnt) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("Wrote %d bytes, expected %d\n", written, cnt));
+            goto done;
         }
     }
 
-    ret = close(ifd);
-    ifd = -1;
-    if (ret != 0) {



More information about the Pkg-sssd-devel mailing list