]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/smack-setup.c
Merge pull request #17732 from yuwata/core-use-synthetic_errno
[thirdparty/systemd.git] / src / core / smack-setup.c
index f05db215e0c47d23736ba301a89c0ca97bb74703..8cc1696a4fa47b754f83e207bcdf3251a79fca03 100644 (file)
@@ -1,31 +1,15 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 /***
-  This file is part of systemd.
-
-  Copyright (C) 2013 Intel Corporation
+  Copyright © 2013 Intel Corporation
   Authors:
         Nathaniel Chen <nathaniel.chen@intel.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2.1 of the License,
-  or (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "dirent-util.h"
 
 #if ENABLE_SMACK
 
-static int write_access2_rules(const char* srcdir) {
+static int fdopen_unlocked_at(int dfd, const char *dir, const char *name, int *status, FILE **ret_file) {
+        int fd, r;
+        FILE *f;
+
+        fd = openat(dfd, name, O_RDONLY|O_CLOEXEC);
+        if (fd < 0) {
+                if (*status == 0)
+                        *status = -errno;
+
+                return log_warning_errno(errno, "Failed to open \"%s/%s\": %m", dir, name);
+        }
+
+        r = fdopen_unlocked(fd, "r", &f);
+        if (r < 0) {
+                if (*status == 0)
+                        *status = r;
+
+                safe_close(fd);
+                return log_error_errno(r, "Failed to open \"%s/%s\": %m", dir, name);
+        }
+
+        *ret_file = f;
+        return 0;
+}
+
+static int write_access2_rules(const char *srcdir) {
         _cleanup_close_ int load2_fd = -1, change_fd = -1;
         _cleanup_closedir_ DIR *dir = NULL;
         struct dirent *entry;
-        char buf[NAME_MAX];
-        int dfd = -1;
-        int r = 0;
+        int dfd = -1, r = 0;
 
         load2_fd = open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (load2_fd < 0)  {
@@ -73,37 +80,27 @@ static int write_access2_rules(const char* srcdir) {
         assert(dfd >= 0);
 
         FOREACH_DIRENT(entry, dir, return 0) {
-                int fd;
                 _cleanup_fclose_ FILE *policy = NULL;
 
+                dirent_ensure_type(dir, entry);
                 if (!dirent_is_file(entry))
                         continue;
 
-                fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
-                if (fd < 0) {
-                        if (r == 0)
-                                r = -errno;
-                        log_warning_errno(errno, "Failed to open '%s': %m", entry->d_name);
-                        continue;
-                }
-
-                policy = fdopen(fd, "re");
-                if (!policy) {
-                        if (r == 0)
-                                r = -errno;
-                        safe_close(fd);
-                        log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
+                if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
                         continue;
-                }
 
                 /* load2 write rules in the kernel require a line buffered stream */
-                FOREACH_LINE(buf, policy,
-                             log_error_errno(errno, "Failed to read line from '%s': %m",
-                                             entry->d_name)) {
-
-                        _cleanup_free_ char *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
+                for (;;) {
+                        _cleanup_free_ char *buf = NULL, *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
+                        int q;
+
+                        q = read_line(policy, NAME_MAX, &buf);
+                        if (q < 0)
+                                return log_error_errno(q, "Failed to read line from '%s': %m", entry->d_name);
+                        if (q == 0)
+                                break;
 
-                        if (isempty(truncate_nl(buf)))
+                        if (isempty(buf) || strchr(COMMENTS, buf[0]))
                                 continue;
 
                         /* if 3 args -> load rule   : subject object access1 */
@@ -116,7 +113,7 @@ static int write_access2_rules(const char* srcdir) {
                         if (write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)) < 0) {
                                 if (r == 0)
                                         r = -errno;
-                                log_error_errno(errno, "Failed to write '%s' to '%s' in '%s'",
+                                log_error_errno(errno, "Failed to write '%s' to '%s' in '%s': %m",
                                                 buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry->d_name);
                         }
                 }
@@ -125,13 +122,11 @@ static int write_access2_rules(const char* srcdir) {
         return r;
 }
 
-static int write_cipso2_rules(const charsrcdir) {
+static int write_cipso2_rules(const char *srcdir) {
         _cleanup_close_ int cipso2_fd = -1;
         _cleanup_closedir_ DIR *dir = NULL;
         struct dirent *entry;
-        char buf[NAME_MAX];
-        int dfd = -1;
-        int r = 0;
+        int dfd = -1, r = 0;
 
         cipso2_fd = open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (cipso2_fd < 0)  {
@@ -152,41 +147,33 @@ static int write_cipso2_rules(const char* srcdir) {
         assert(dfd >= 0);
 
         FOREACH_DIRENT(entry, dir, return 0) {
-                int fd;
                 _cleanup_fclose_ FILE *policy = NULL;
 
+                dirent_ensure_type(dir, entry);
                 if (!dirent_is_file(entry))
                         continue;
 
-                fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
-                if (fd < 0) {
-                        if (r == 0)
-                                r = -errno;
-                        log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
+                if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
                         continue;
-                }
-
-                policy = fdopen(fd, "re");
-                if (!policy) {
-                        if (r == 0)
-                                r = -errno;
-                        safe_close(fd);
-                        log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
-                        continue;
-                }
 
                 /* cipso2 write rules in the kernel require a line buffered stream */
-                FOREACH_LINE(buf, policy,
-                             log_error_errno(errno, "Failed to read line from '%s': %m",
-                                             entry->d_name)) {
+                for (;;) {
+                        _cleanup_free_ char *buf = NULL;
+                        int q;
+
+                        q = read_line(policy, NAME_MAX, &buf);
+                        if (q < 0)
+                                return log_error_errno(q, "Failed to read line from '%s': %m", entry->d_name);
+                        if (q == 0)
+                                break;
 
-                        if (isempty(truncate_nl(buf)))
+                        if (isempty(buf) || strchr(COMMENTS, buf[0]))
                                 continue;
 
                         if (write(cipso2_fd, buf, strlen(buf)) < 0) {
                                 if (r == 0)
                                         r = -errno;
-                                log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s'",
+                                log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s': %m",
                                                 buf, entry->d_name);
                                 break;
                         }
@@ -196,13 +183,11 @@ static int write_cipso2_rules(const char* srcdir) {
         return r;
 }
 
-static int write_netlabel_rules(const charsrcdir) {
+static int write_netlabel_rules(const char *srcdir) {
         _cleanup_fclose_ FILE *dst = NULL;
         _cleanup_closedir_ DIR *dir = NULL;
         struct dirent *entry;
-        char buf[NAME_MAX];
-        int dfd = -1;
-        int r = 0;
+        int dfd = -1, r = 0;
 
         dst = fopen("/sys/fs/smackfs/netlabel", "we");
         if (!dst)  {
@@ -223,40 +208,33 @@ static int write_netlabel_rules(const char* srcdir) {
         assert(dfd >= 0);
 
         FOREACH_DIRENT(entry, dir, return 0) {
-                int fd;
                 _cleanup_fclose_ FILE *policy = NULL;
 
-                fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
-                if (fd < 0) {
-                        if (r == 0)
-                                r = -errno;
-                        log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
+                if (fdopen_unlocked_at(dfd, srcdir, entry->d_name, &r, &policy) < 0)
                         continue;
-                }
-
-                policy = fdopen(fd, "re");
-                if (!policy) {
-                        if (r == 0)
-                                r = -errno;
-                        safe_close(fd);
-                        log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
-                        continue;
-                }
 
                 /* load2 write rules in the kernel require a line buffered stream */
-                FOREACH_LINE(buf, policy,
-                             log_error_errno(errno, "Failed to read line from %s: %m",
-                                       entry->d_name)) {
-                        if (!fputs_unlocked(buf, dst)) {
+                for (;;) {
+                        _cleanup_free_ char *buf = NULL;
+                        int q;
+
+                        q = read_line(policy, NAME_MAX, &buf);
+                        if (q < 0)
+                                return log_error_errno(q, "Failed to read line from %s: %m", entry->d_name);
+                        if (q == 0)
+                                break;
+
+                        if (!fputs(buf, dst)) {
                                 if (r == 0)
                                         r = -EINVAL;
-                                log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel");
+                                log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel: %m");
                                 break;
                         }
-                        if (fflush(dst)) {
+                        q = fflush_and_check(dst);
+                        if (q < 0) {
                                 if (r == 0)
-                                        r = -errno;
-                                log_error_errno(errno, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
+                                        r = q;
+                                log_error_errno(q, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
                                 break;
                         }
                 }
@@ -270,20 +248,27 @@ static int write_onlycap_list(void) {
         _cleanup_free_ char *list = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         size_t len = 0, allocated = 0;
-        char buf[LINE_MAX];
         int r;
 
         f = fopen("/etc/smack/onlycap", "re");
         if (!f) {
                 if (errno != ENOENT)
-                        log_warning_errno(errno, "Failed to read '/etc/smack/onlycap'");
+                        log_warning_errno(errno, "Failed to read '/etc/smack/onlycap': %m");
+
                 return errno == ENOENT ? ENOENT : -errno;
         }
 
-        FOREACH_LINE(buf, f, return -errno) {
+        for (;;) {
+                _cleanup_free_ char *buf = NULL;
                 size_t l;
 
-                if (isempty(truncate_nl(buf)) || strchr(COMMENTS, *buf))
+                r = read_line(f, LONG_LINE_MAX, &buf);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to read line from /etc/smack/onlycap: %m");
+                if (r == 0)
+                        break;
+
+                if (isempty(buf) || strchr(COMMENTS, *buf))
                         continue;
 
                 l = strlen(buf);
@@ -294,7 +279,7 @@ static int write_onlycap_list(void) {
                 len += l + 1;
         }
 
-        if (!len)
+        if (len == 0)
                 return 0;
 
         list[len - 1] = 0;
@@ -302,13 +287,13 @@ static int write_onlycap_list(void) {
         onlycap_fd = open("/sys/fs/smackfs/onlycap", O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (onlycap_fd < 0) {
                 if (errno != ENOENT)
-                        log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/onlycap'");
+                        log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/onlycap': %m");
                 return -errno; /* negative error */
         }
 
         r = write(onlycap_fd, list, len);
         if (r < 0)
-                return log_error_errno(errno, "Failed to write onlycap list(%s) to '/sys/fs/smackfs/onlycap'", list);
+                return log_error_errno(errno, "Failed to write onlycap list(%s) to '/sys/fs/smackfs/onlycap': %m", list);
 
         return 0;
 }
@@ -340,17 +325,17 @@ int mac_smack_setup(bool *loaded_policy) {
         }
 
 #ifdef SMACK_RUN_LABEL
-        r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
+        r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m");
-        r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0);
+        r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m");
         r = write_string_file("/sys/fs/smackfs/netlabel",
-                              "0.0.0.0/0 " SMACK_RUN_LABEL, 0);
+                              "0.0.0.0/0 " SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m");
-        r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0);
+        r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
 #endif
@@ -399,8 +384,7 @@ int mac_smack_setup(bool *loaded_policy) {
                 log_info("Successfully wrote Smack onlycap list.");
                 break;
         default:
-                log_emergency_errno(r, "Failed to write Smack onlycap list.");
-                return r;
+                return log_emergency_errno(r, "Failed to write Smack onlycap list: %m");
         }
 
         *loaded_policy = true;