Pablo Greco 48fc63
From bac7488e06e379628653fb2f3ece0a30414ff84e Mon Sep 17 00:00:00 2001
Pablo Greco 48fc63
From: Lennart Poettering <lennart@poettering.net>
Pablo Greco 48fc63
Date: Mon, 22 Jan 2018 21:03:53 +0100
Pablo Greco 48fc63
Subject: [PATCH] tmpfiles: change ownership of symlinks too
Pablo Greco 48fc63
Pablo Greco 48fc63
Ownership is supported for symlinks, too, only file modes are not.
Pablo Greco 48fc63
Support that too.
Pablo Greco 48fc63
Pablo Greco 48fc63
Fixes: #7509
Pablo Greco 48fc63
(cherry picked from commit 51207ca134716a0dee5fd763a6c39204be849eb1)
Pablo Greco 48fc63
Pablo Greco 48fc63
Resolves: #1620110
Pablo Greco 48fc63
---
Pablo Greco 48fc63
 src/shared/macro.h      |  7 +++++++
Pablo Greco 48fc63
 src/tmpfiles/tmpfiles.c | 41 +++++++++++++++++++++--------------------
Pablo Greco 48fc63
 2 files changed, 28 insertions(+), 20 deletions(-)
Pablo Greco 48fc63
Pablo Greco 48fc63
diff --git a/src/shared/macro.h b/src/shared/macro.h
Pablo Greco 48fc63
index 7a57f4e5b1..26df270d51 100644
Pablo Greco 48fc63
--- a/src/shared/macro.h
Pablo Greco 48fc63
+++ b/src/shared/macro.h
Pablo Greco 48fc63
@@ -125,6 +125,13 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
Pablo Greco 48fc63
 
Pablo Greco 48fc63
 #define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
Pablo Greco 48fc63
 
Pablo Greco 48fc63
+/*
Pablo Greco 48fc63
+ * STRLEN - return the length of a string literal, minus the trailing NUL byte.
Pablo Greco 48fc63
+ *          Contrary to strlen(), this is a constant expression.
Pablo Greco 48fc63
+ * @x: a string literal.
Pablo Greco 48fc63
+ */
Pablo Greco 48fc63
+#define STRLEN(x) (sizeof(""x"") - 1)
Pablo Greco 48fc63
+
Pablo Greco 48fc63
 /*
Pablo Greco 48fc63
  * container_of - cast a member of a structure out to the containing structure
Pablo Greco 48fc63
  * @ptr: the pointer to the member.
Pablo Greco 48fc63
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
Pablo Greco 48fc63
index 0b17b5908e..663f6c8b2d 100644
Pablo Greco 48fc63
--- a/src/tmpfiles/tmpfiles.c
Pablo Greco 48fc63
+++ b/src/tmpfiles/tmpfiles.c
Pablo Greco 48fc63
@@ -591,6 +591,7 @@ finish:
Pablo Greco 48fc63
 }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
 static int path_set_perms(Item *i, const char *path) {
Pablo Greco 48fc63
+        char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
Pablo Greco 48fc63
         _cleanup_close_ int fd = -1;
Pablo Greco 48fc63
         struct stat st;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
@@ -624,14 +625,12 @@ static int path_set_perms(Item *i, const char *path) {
Pablo Greco 48fc63
         if (i->type == EMPTY_DIRECTORY && !S_ISDIR(st.st_mode))
Pablo Greco 48fc63
                 return log_error_errno(EEXIST, "'%s' already exists and is not a directory. ", path);
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-        if (S_ISLNK(st.st_mode))
Pablo Greco 48fc63
-                log_debug("Skipping mode an owner fix for symlink %s.", path);
Pablo Greco 48fc63
-        else {
Pablo Greco 48fc63
-                char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
Pablo Greco 48fc63
-                xsprintf(fn, "/proc/self/fd/%i", fd);
Pablo Greco 48fc63
+        xsprintf(fn, "/proc/self/fd/%i", fd);
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                /* not using i->path directly because it may be a glob */
Pablo Greco 48fc63
-                if (i->mode_set) {
Pablo Greco 48fc63
+        if (i->mode_set) {
Pablo Greco 48fc63
+                if (S_ISLNK(st.st_mode))
Pablo Greco 48fc63
+                        log_debug("Skipping mode fix for symlink %s.", path);
Pablo Greco 48fc63
+                else {
Pablo Greco 48fc63
                         mode_t m = i->mode;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                         if (i->mask_perms) {
Pablo Greco 48fc63
@@ -646,25 +645,27 @@ static int path_set_perms(Item *i, const char *path) {
Pablo Greco 48fc63
                         }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                         if (m == (st.st_mode & 07777))
Pablo Greco 48fc63
-                                log_debug("\"%s\" has right mode %o", path, st.st_mode);
Pablo Greco 48fc63
+                                log_debug("\"%s\" has correct mode %o already.", path, st.st_mode);
Pablo Greco 48fc63
                         else {
Pablo Greco 48fc63
-                                log_debug("chmod \"%s\" to mode %o", path, m);
Pablo Greco 48fc63
+                                log_debug("Changing \"%s\" to mode %o.", path, m);
Pablo Greco 48fc63
+
Pablo Greco 48fc63
                                 if (chmod(fn, m) < 0)
Pablo Greco 48fc63
                                         return log_error_errno(errno, "chmod(%s) failed: %m", path);
Pablo Greco 48fc63
                         }
Pablo Greco 48fc63
                 }
Pablo Greco 48fc63
+        }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                if ((i->uid != st.st_uid || i->gid != st.st_gid) &&
Pablo Greco 48fc63
-                    (i->uid_set || i->gid_set)) {
Pablo Greco 48fc63
-                        log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
Pablo Greco 48fc63
-                                  path,
Pablo Greco 48fc63
-                                  i->uid_set ? i->uid : UID_INVALID,
Pablo Greco 48fc63
-                                  i->gid_set ? i->gid : GID_INVALID);
Pablo Greco 48fc63
-                        if (chown(fn,
Pablo Greco 48fc63
-                                  i->uid_set ? i->uid : UID_INVALID,
Pablo Greco 48fc63
-                                  i->gid_set ? i->gid : GID_INVALID) < 0)
Pablo Greco 48fc63
-                        return log_error_errno(errno, "chown(%s) failed: %m", path);
Pablo Greco 48fc63
-                }
Pablo Greco 48fc63
+        if ((i->uid != st.st_uid || i->gid != st.st_gid) &&
Pablo Greco 48fc63
+            (i->uid_set || i->gid_set)) {
Pablo Greco 48fc63
+                log_debug("Changing \"%s\" to owner "UID_FMT":"GID_FMT,
Pablo Greco 48fc63
+                          path,
Pablo Greco 48fc63
+                          i->uid_set ? i->uid : UID_INVALID,
Pablo Greco 48fc63
+                          i->gid_set ? i->gid : GID_INVALID);
Pablo Greco 48fc63
+
Pablo Greco 48fc63
+                if (chown(fn,
Pablo Greco 48fc63
+                          i->uid_set ? i->uid : UID_INVALID,
Pablo Greco 48fc63
+                          i->gid_set ? i->gid : GID_INVALID) < 0)
Pablo Greco 48fc63
+                        return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn);
Pablo Greco 48fc63
         }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
         fd = safe_close(fd);