[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