]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
creds: open up access to clients via Polkit
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Nov 2023 21:22:27 +0000 (22:22 +0100)
committerLuca Boccassi <bluca@debian.org>
Wed, 3 Jan 2024 10:53:52 +0000 (11:53 +0100)
Use auth_admin_keep, so that users don't have to re-auth interactively
again and again when encrypting/decrypting batches of credentials.

src/creds/creds.c
src/creds/io.systemd.credentials.policy [new file with mode: 0644]
src/creds/meson.build
units/systemd-creds.socket

index ed39ffe51e138f46f99cec4e507bef7b50431e2b..5586baff9a49c882318fa668828e6194fb0462c8 100644 (file)
@@ -4,6 +4,7 @@
 #include <unistd.h>
 
 #include "build.h"
+#include "bus-polkit.h"
 #include "creds-util.h"
 #include "dirent-util.h"
 #include "escape.h"
@@ -983,6 +984,7 @@ static int vl_method_encrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
                 { "data",      JSON_VARIANT_STRING,        json_dispatch_unbase64_iovec, offsetof(MethodEncryptParameters, data),      0 },
                 { "timestamp", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64,         offsetof(MethodEncryptParameters, timestamp), 0 },
                 { "notAfter",  _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64,         offsetof(MethodEncryptParameters, not_after), 0 },
+                VARLINK_DISPATCH_POLKIT_FIELD,
                 {}
         };
         _cleanup_(method_encrypt_parameters_done) MethodEncryptParameters p = {
@@ -990,6 +992,7 @@ static int vl_method_encrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
                 .not_after = UINT64_MAX,
         };
         _cleanup_(iovec_done) struct iovec output = {};
+        Hashmap **polkit_registry = ASSERT_PTR(userdata);
         int r;
 
         assert(link);
@@ -1010,6 +1013,16 @@ static int vl_method_encrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
         if (p.not_after != UINT64_MAX && p.not_after < p.timestamp)
                 return varlink_error_invalid_parameter_name(link, "notAfter");
 
+        r = varlink_verify_polkit_async(
+                        link,
+                        /* bus= */ NULL,
+                        "io.systemd.credentials.encrypt",
+                        /* details= */ NULL,
+                        /* good_user= */ UID_INVALID,
+                        polkit_registry);
+        if (r <= 0)
+                return r;
+
         r = encrypt_credential_and_warn(
                         arg_with_key,
                         p.name,
@@ -1051,15 +1064,17 @@ static void method_decrypt_parameters_done(MethodDecryptParameters *p) {
 static int vl_method_decrypt(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
 
         static const JsonDispatch dispatch_table[] = {
-                { "name",      JSON_VARIANT_STRING,        json_dispatch_const_string,   offsetof(MethodDecryptParameters, name),      0 },
-                { "blob",      JSON_VARIANT_STRING,        json_dispatch_unbase64_iovec, offsetof(MethodDecryptParameters, blob),      0 },
-                { "timestamp", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64,         offsetof(MethodDecryptParameters, timestamp), 0 },
+                { "name",      JSON_VARIANT_STRING,        json_dispatch_const_string,   offsetof(MethodDecryptParameters, name),      0              },
+                { "blob",      JSON_VARIANT_STRING,        json_dispatch_unbase64_iovec, offsetof(MethodDecryptParameters, blob),      JSON_MANDATORY },
+                { "timestamp", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64,         offsetof(MethodDecryptParameters, timestamp), 0              },
+                VARLINK_DISPATCH_POLKIT_FIELD,
                 {}
         };
         _cleanup_(method_decrypt_parameters_done) MethodDecryptParameters p = {
                 .timestamp = UINT64_MAX,
         };
         _cleanup_(iovec_done_erase) struct iovec output = {};
+        Hashmap **polkit_registry = ASSERT_PTR(userdata);
         int r;
 
         assert(link);
@@ -1073,11 +1088,19 @@ static int vl_method_decrypt(Varlink *link, JsonVariant *parameters, VarlinkMeth
 
         if (p.name && !credential_name_valid(p.name))
                 return varlink_error_invalid_parameter_name(link, "name");
-        if (!p.blob.iov_base)
-                return varlink_error_invalid_parameter_name(link, "blob");
         if (p.timestamp == UINT64_MAX)
                 p.timestamp = now(CLOCK_REALTIME);
 
+        r = varlink_verify_polkit_async(
+                        link,
+                        /* bus= */ NULL,
+                        "io.systemd.credentials.decrypt",
+                        /* details= */ NULL,
+                        /* good_user= */ UID_INVALID,
+                        polkit_registry);
+        if (r <= 0)
+                return r;
+
         r = decrypt_credential_and_warn(
                         p.name,
                         p.timestamp,
@@ -1116,10 +1139,11 @@ static int run(int argc, char *argv[]) {
 
         if (arg_varlink) {
                 _cleanup_(varlink_server_unrefp) VarlinkServer *varlink_server = NULL;
+                _cleanup_(hashmap_freep) Hashmap *polkit_registry = NULL;
 
                 /* Invocation as Varlink service */
 
-                r = varlink_server_new(&varlink_server, VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_INHERIT_USERDATA);
+                r = varlink_server_new(&varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
                 if (r < 0)
                         return log_error_errno(r, "Failed to allocate Varlink server: %m");
 
@@ -1134,6 +1158,8 @@ static int run(int argc, char *argv[]) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to bind Varlink methods: %m");
 
+                varlink_server_set_userdata(varlink_server, &polkit_registry);
+
                 r = varlink_server_loop_auto(varlink_server);
                 if (r < 0)
                         return log_error_errno(r, "Failed to run Varlink event loop: %m");
diff --git a/src/creds/io.systemd.credentials.policy b/src/creds/io.systemd.credentials.policy
new file mode 100644 (file)
index 0000000..f94571b
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+        "https://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1-or-later
+
+  This file is part of systemd.
+
+  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.
+-->
+
+<policyconfig>
+
+        <vendor>The systemd Project</vendor>
+        <vendor_url>https://systemd.io</vendor_url>
+
+        <action id="io.systemd.credentials.encrypt">
+                <description gettext-domain="systemd">Allow encryption and signing of system credentials.</description>
+                <message gettext-domain="systemd">Authentication is required for an application to encrypt and sign a system credential.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
+        <action id="io.systemd.credentials.decrypt">
+                <description gettext-domain="systemd">Allow decryption of system credentials.</description>
+                <message gettext-domain="systemd">Authentication is required for an application to decrypto a system credential.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+</policyconfig>
index 85572568f6c0b85c91676b569962fc9dac0e613c..24833110d532239c7df39fc0d46eade8bdc05c65 100644 (file)
@@ -23,3 +23,6 @@ if install_sysconfdir
         install_emptydir(sysconfdir / 'credstore.encrypted',
                          install_mode : 'rwx------')
 endif
+
+install_data('io.systemd.credentials.policy',
+             install_dir : polkitpolicydir)
index 794fac19a848b0afef6c005c78991f3fb25eda9a..ac72ccc82f1d25d254e3740fa5f05214b3bd1fff 100644 (file)
@@ -16,7 +16,7 @@ Before=sockets.target
 [Socket]
 ListenStream=/run/systemd/io.systemd.Credentials
 FileDescriptorName=varlink
-SocketMode=0600
+SocketMode=0666
 Accept=yes
 
 [Install]