]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
user-record: extend user records with an ambient and bounding caps set field
authorLennart Poettering <lennart@poettering.net>
Fri, 17 Feb 2023 21:22:16 +0000 (22:22 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 28 Feb 2023 20:42:29 +0000 (21:42 +0100)
In particular the ambieht caps field is useful: we can use it later to
pass caps such as CAP_WAKE_ALARM to regular users on login.

src/shared/user-record-show.c
src/shared/user-record.c
src/shared/user-record.h

index da181c6078af14559d2436f9ab92c5cb4aaa7834..28fa7a86324892cd3425808dd7e1e5ca9678007a 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include "cap-list.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "process-util.h"
@@ -287,6 +288,22 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
         if (hr->access_mode != MODE_INVALID)
                 printf(" Access Mode: 0%03o\n", user_record_access_mode(hr));
 
+        uint64_t caps = user_record_capability_bounding_set(hr);
+        if (caps != UINT64_MAX) {
+                _cleanup_free_ char *scaps = NULL;
+
+                (void) capability_set_to_string_negative(caps, &scaps);
+                printf(" Bound. Caps: %s\n", strna(scaps));
+        }
+
+        caps = user_record_capability_ambient_set(hr);
+        if (caps != UINT64_MAX) {
+                _cleanup_free_ char *scaps = NULL;
+
+                (void) capability_set_to_string(caps, &scaps);
+                printf("Ambient Caps: %s\n", strna(scaps));
+        }
+
         if (storage == USER_LUKS) {
                 printf("LUKS Discard: online=%s offline=%s\n", yes_no(user_record_luks_discard(hr)), yes_no(user_record_luks_offline_discard(hr)));
 
index 06bc699572f28e7ff2dc11a60a6d5476b0939ff8..b51d8add1af5f75b547a491de40e842bebd33667 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <sys/mount.h>
 
+#include "cap-list.h"
 #include "cgroup-util.h"
 #include "dns-domain.h"
 #include "env-util.h"
@@ -165,6 +166,8 @@ static UserRecord* user_record_free(UserRecord *h) {
         free(h->home_directory_auto);
 
         strv_free(h->member_of);
+        strv_free(h->capability_bounding_set);
+        strv_free(h->capability_ambient_set);
 
         free(h->file_system_type);
         free(h->luks_cipher);
@@ -1203,6 +1206,8 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
                 { "uid",                        JSON_VARIANT_UNSIGNED,      json_dispatch_uid_gid,                offsetof(UserRecord, uid),                           0         },
                 { "gid",                        JSON_VARIANT_UNSIGNED,      json_dispatch_uid_gid,                offsetof(UserRecord, gid),                           0         },
                 { "memberOf",                   JSON_VARIANT_ARRAY,         json_dispatch_user_group_list,        offsetof(UserRecord, member_of),                     JSON_RELAX},
+                { "capabilityBoundingSet",      JSON_VARIANT_ARRAY,         json_dispatch_strv,                   offsetof(UserRecord, capability_bounding_set),       JSON_SAFE },
+                { "capabilityAmbientSet",       JSON_VARIANT_ARRAY,         json_dispatch_strv,                   offsetof(UserRecord, capability_ambient_set),        JSON_SAFE },
                 { "fileSystemType",             JSON_VARIANT_STRING,        json_dispatch_string,                 offsetof(UserRecord, file_system_type),              JSON_SAFE },
                 { "partitionUuid",              JSON_VARIANT_STRING,        json_dispatch_id128,                  offsetof(UserRecord, partition_uuid),                0         },
                 { "luksUuid",                   JSON_VARIANT_STRING,        json_dispatch_id128,                  offsetof(UserRecord, luks_uuid),                     0         },
@@ -1557,6 +1562,8 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
                 { "uid",                        JSON_VARIANT_UNSIGNED,      json_dispatch_uid_gid,                offsetof(UserRecord, uid),                           0         },
                 { "gid",                        JSON_VARIANT_UNSIGNED,      json_dispatch_uid_gid,                offsetof(UserRecord, gid),                           0         },
                 { "memberOf",                   JSON_VARIANT_ARRAY,         json_dispatch_user_group_list,        offsetof(UserRecord, member_of),                     JSON_RELAX},
+                { "capabilityBoundingSet",      JSON_VARIANT_ARRAY,         json_dispatch_strv,                   offsetof(UserRecord, capability_bounding_set),       JSON_SAFE },
+                { "capabilityAmbientSet",       JSON_VARIANT_ARRAY,         json_dispatch_strv,                   offsetof(UserRecord, capability_ambient_set),        JSON_SAFE },
                 { "fileSystemType",             JSON_VARIANT_STRING,        json_dispatch_string,                 offsetof(UserRecord, file_system_type),              JSON_SAFE },
                 { "partitionUuid",              JSON_VARIANT_STRING,        json_dispatch_id128,                  offsetof(UserRecord, partition_uuid),                0         },
                 { "luksUuid",                   JSON_VARIANT_STRING,        json_dispatch_id128,                  offsetof(UserRecord, luks_uuid),                     0         },
@@ -2018,6 +2025,43 @@ uint64_t user_record_rebalance_weight(UserRecord *h) {
         return h->rebalance_weight;
 }
 
+static uint64_t parse_caps_strv(char **l) {
+        uint64_t c = 0;
+        int r;
+
+        STRV_FOREACH(i, l) {
+                r = capability_from_name(*i);
+                if (r < 0)
+                        log_debug_errno(r, "Don't know capability '%s', ignoring: %m", *i);
+                else
+                        c |= UINT64_C(1) << r;
+        }
+
+        return c;
+}
+
+uint64_t user_record_capability_bounding_set(UserRecord *h) {
+        assert(h);
+
+        /* Returns UINT64_MAX if no bounding set is configured (!) */
+
+        if (!h->capability_bounding_set)
+                return UINT64_MAX;
+
+        return parse_caps_strv(h->capability_bounding_set);
+}
+
+uint64_t user_record_capability_ambient_set(UserRecord *h) {
+        assert(h);
+
+        /* Returns UINT64_MAX if no ambient set is configured (!) */
+
+        if (!h->capability_ambient_set)
+                return UINT64_MAX;
+
+        return parse_caps_strv(h->capability_ambient_set) & user_record_capability_bounding_set(h);
+}
+
 uint64_t user_record_ratelimit_next_try(UserRecord *h) {
         assert(h);
 
index 73fb86cc94520e6a8976a49ec743b43d85befbdf..298dc244fe449fbfcba231127fcf4c02133c8a97 100644 (file)
@@ -366,6 +366,9 @@ typedef struct UserRecord {
         RecoveryKey *recovery_key;
         size_t n_recovery_key;
 
+        char **capability_bounding_set;
+        char **capability_ambient_set;
+
         JsonVariant *json;
 } UserRecord;
 
@@ -410,6 +413,8 @@ bool user_record_can_authenticate(UserRecord *h);
 bool user_record_drop_caches(UserRecord *h);
 AutoResizeMode user_record_auto_resize_mode(UserRecord *h);
 uint64_t user_record_rebalance_weight(UserRecord *h);
+uint64_t user_record_capability_bounding_set(UserRecord *h);
+uint64_t user_record_capability_ambient_set(UserRecord *h);
 
 int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret);