]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/condition.c
tree-wide: make use of getpid_cached() wherever we can
[thirdparty/systemd.git] / src / shared / condition.c
index f13fa6a9fdc548383be77be2dbf2b706b85c1e92..103f8d2e3952944b0643f62494effc01043d99db 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
+#include "process-util.h"
 #include "selinux-util.h"
 #include "smack-util.h"
 #include "stat-util.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "user-util.h"
 #include "util.h"
 #include "virt.h"
 
@@ -111,9 +114,8 @@ static int condition_test_kernel_command_line(Condition *c) {
                 return r;
 
         equal = !!strchr(c->parameter, '=');
-        p = line;
 
-        for (;;) {
+        for (p = line;;) {
                 _cleanup_free_ char *word = NULL;
                 bool found;
 
@@ -139,6 +141,60 @@ static int condition_test_kernel_command_line(Condition *c) {
         return false;
 }
 
+static int condition_test_user(Condition *c) {
+        uid_t id;
+        int r;
+        _cleanup_free_ char *username = NULL;
+        const char *u;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_USER);
+
+        r = parse_uid(c->parameter, &id);
+        if (r >= 0)
+                return id == getuid() || id == geteuid();
+
+        if (streq("@system", c->parameter))
+                return getuid() <= SYSTEM_UID_MAX || geteuid() <= SYSTEM_UID_MAX;
+
+        username = getusername_malloc();
+        if (!username)
+                return -ENOMEM;
+
+        if (streq(username, c->parameter))
+                return 1;
+
+        if (getpid_cached() == 1)
+                return streq(c->parameter, "root");
+
+        u = c->parameter;
+        r = get_user_creds(&u, &id, NULL, NULL, NULL);
+        if (r < 0)
+                return 0;
+
+        return id == getuid() || id == geteuid();
+}
+
+static int condition_test_group(Condition *c) {
+        gid_t id;
+        int r;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_GROUP);
+
+        r = parse_gid(c->parameter, &id);
+        if (r >= 0)
+                return in_gid(id);
+
+        /* Avoid any NSS lookups if we are PID1 */
+        if (getpid_cached() == 1)
+                return streq(c->parameter, "root");
+
+        return in_group(c->parameter) > 0;
+}
+
 static int condition_test_virtualization(Condition *c) {
         int b, v;
 
@@ -146,25 +202,24 @@ static int condition_test_virtualization(Condition *c) {
         assert(c->parameter);
         assert(c->type == CONDITION_VIRTUALIZATION);
 
+        if (streq(c->parameter, "private-users"))
+                return running_in_userns();
+
         v = detect_virtualization();
         if (v < 0)
                 return v;
 
         /* First, compare with yes/no */
         b = parse_boolean(c->parameter);
-
-        if (v > 0 && b > 0)
-                return true;
-
-        if (v == 0 && b == 0)
-                return true;
+        if (b >= 0)
+                return b == !!v;
 
         /* Then, compare categorization */
-        if (VIRTUALIZATION_IS_VM(v) && streq(c->parameter, "vm"))
-                return true;
+        if (streq(c->parameter, "vm"))
+                return VIRTUALIZATION_IS_VM(v);
 
-        if (VIRTUALIZATION_IS_CONTAINER(v) && streq(c->parameter, "container"))
-                return true;
+        if (streq(c->parameter, "container"))
+                return VIRTUALIZATION_IS_CONTAINER(v);
 
         /* Finally compare id */
         return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
@@ -237,7 +292,7 @@ static int condition_test_security(Condition *c) {
         assert(c->type == CONDITION_SECURITY);
 
         if (streq(c->parameter, "selinux"))
-                return mac_selinux_have();
+                return mac_selinux_use();
         if (streq(c->parameter, "smack"))
                 return mac_smack_use();
         if (streq(c->parameter, "apparmor"))
@@ -329,9 +384,9 @@ static int condition_test_needs_update(Condition *c) {
                 uint64_t timestamp;
                 int r;
 
-                r = parse_env_file(p, NULL, "TimestampNSec", &timestamp_str, NULL);
+                r = parse_env_file(p, NULL, "TIMESTAMP_NSEC", &timestamp_str, NULL);
                 if (r < 0) {
-                        log_error_errno(-r, "Failed to parse timestamp file '%s', using mtime: %m", p);
+                        log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
                         return true;
                 } else if (r == 0) {
                         log_debug("No data in timestamp file '%s', using mtime", p);
@@ -340,12 +395,11 @@ static int condition_test_needs_update(Condition *c) {
 
                 r = safe_atou64(timestamp_str, &timestamp);
                 if (r < 0) {
-                        log_error_errno(-r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m",
-                                        timestamp_str, p);
+                        log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
                         return true;
                 }
 
-                other.st_mtim.tv_nsec = timestamp % NSEC_PER_SEC;
+                timespec_store(&other.st_mtim, timestamp);
         }
 
         return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
@@ -402,7 +456,7 @@ static int condition_test_path_is_mount_point(Condition *c) {
         assert(c->parameter);
         assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
 
-        return path_is_mount_point(c->parameter, AT_SYMLINK_FOLLOW) > 0;
+        return path_is_mount_point(c->parameter, NULL, AT_SYMLINK_FOLLOW) > 0;
 }
 
 static int condition_test_path_is_read_write(Condition *c) {
@@ -478,6 +532,8 @@ int condition_test(Condition *c) {
                 [CONDITION_ARCHITECTURE] = condition_test_architecture,
                 [CONDITION_NEEDS_UPDATE] = condition_test_needs_update,
                 [CONDITION_FIRST_BOOT] = condition_test_first_boot,
+                [CONDITION_USER] = condition_test_user,
+                [CONDITION_GROUP] = condition_test_group,
                 [CONDITION_NULL] = condition_test_null,
         };
 
@@ -541,6 +597,8 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
+        [CONDITION_USER] = "ConditionUser",
+        [CONDITION_GROUP] = "ConditionGroup",
         [CONDITION_NULL] = "ConditionNull"
 };
 
@@ -565,6 +623,8 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
         [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
         [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
+        [CONDITION_USER] = "AssertUser",
+        [CONDITION_GROUP] = "AssertGroup",
         [CONDITION_NULL] = "AssertNull"
 };