]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ask-password: add Varlink API for querying passwords from the user
authorLennart Poettering <lennart@poettering.net>
Wed, 6 Nov 2024 10:56:46 +0000 (11:56 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 2 Jan 2025 15:39:05 +0000 (16:39 +0100)
This turns systemd-ask-password into a small Varlink service, so that
there's an standard IPC way to ask for a password. It mostly directly
exposes the functionality of the Varlink service.

12 files changed:
src/ask-password/ask-password.c
src/ask-password/io.systemd.ask-password.policy [new file with mode: 0644]
src/shared/meson.build
src/shared/varlink-io.systemd.AskPassword.c [new file with mode: 0644]
src/shared/varlink-io.systemd.AskPassword.h [new file with mode: 0644]
src/test/test-varlink-idl.c
units/meson.build
units/systemd-ask-password.socket [new file with mode: 0644]
units/systemd-ask-password@.service [new file with mode: 0644]
units/user/meson.build
units/user/systemd-ask-password.socket [new file with mode: 0644]
units/user/systemd-ask-password@.service [new file with mode: 0644]

index 154aaa030e8a3c69be808a98f9d453d85309224a..551dcb8b2727c93ceb116fa4ed0c57f46a7516d8 100644 (file)
@@ -5,16 +5,23 @@
 #include <stddef.h>
 #include <unistd.h>
 
+#include "sd-varlink.h"
+
 #include "ask-password-api.h"
 #include "build.h"
+#include "bus-polkit.h"
 #include "constants.h"
+#include "json-util.h"
 #include "log.h"
 #include "macro.h"
 #include "main-func.h"
 #include "parse-argument.h"
 #include "pretty-print.h"
+#include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "varlink-io.systemd.AskPassword.h"
+#include "varlink-util.h"
 
 static const char *arg_icon = NULL;
 static const char *arg_id = NULL;               /* identifier for 'ask-password' protocol */
@@ -26,6 +33,7 @@ static bool arg_multiple = false;
 static bool arg_no_output = false;
 static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE;
 static bool arg_newline = true;
+static bool arg_varlink = false;
 
 STATIC_DESTRUCTOR_REGISTER(arg_message, freep);
 
@@ -213,7 +221,7 @@ static int parse_argv(int argc, char *argv[]) {
         else {
                 r = parse_boolean_argument("--emoji=", emoji, NULL);
                 if (r < 0)
-                         return r;
+                        return r;
 
                 SET_FLAG(arg_flags, ASK_PASSWORD_HIDE_EMOJI, !r);
         }
@@ -232,9 +240,164 @@ static int parse_argv(int argc, char *argv[]) {
                         return log_oom();
         }
 
+        r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
+        if (r < 0)
+                return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
+        if (r > 0)
+                arg_varlink = true;
+
         return 1;
 }
 
+typedef enum EchoMode {
+        ECHO_OFF,
+        ECHO_ON,
+        ECHO_MASKED,
+        _ECHO_MODE_MAX,
+        _ECHO_MODE_INVALID = -EINVAL,
+} EchoMode;
+
+static const char* echo_mode_table[_ECHO_MODE_MAX] = {
+        [ECHO_OFF]    = "off",
+        [ECHO_ON]     = "on",
+        [ECHO_MASKED] = "masked",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(echo_mode, EchoMode, ECHO_ON);
+
+static JSON_DISPATCH_ENUM_DEFINE(dispatch_echo_mode, EchoMode, echo_mode_from_string);
+
+typedef struct MethodAskParameters {
+        const char *message;
+        const char *keyring;
+        const char *icon;
+        const char *id;
+        uint64_t timeout_usec;
+        uint64_t until_usec;
+        int accept_cached;
+        int push_cache;
+        EchoMode echo_mode;
+} MethodAskParameters;
+
+static int vl_method_ask(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+
+        static const sd_json_dispatch_field dispatch_table[] = {
+                { "message",      SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MethodAskParameters, message),       0 },
+                { "keyname",      SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MethodAskParameters, keyring),       0 },
+                { "icon",         SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MethodAskParameters, icon),          0 },
+                { "id",           SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(MethodAskParameters, id),            0 },
+                { "timeoutUSec",  _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,       offsetof(MethodAskParameters, timeout_usec),  0 },
+                { "untilUSec",    _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64,       offsetof(MethodAskParameters, until_usec),    0 },
+                { "acceptCached", SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_tristate,     offsetof(MethodAskParameters, accept_cached), 0 },
+                { "pushCache",    SD_JSON_VARIANT_BOOLEAN,       sd_json_dispatch_tristate,     offsetof(MethodAskParameters, push_cache) ,   0 },
+                { "echo",         SD_JSON_VARIANT_STRING,        dispatch_echo_mode,            offsetof(MethodAskParameters, echo_mode),     0 },
+                VARLINK_DISPATCH_POLKIT_FIELD,
+                {}
+        };
+
+        Hashmap **polkit_registry = ASSERT_PTR(userdata);
+        MethodAskParameters p = {
+                .timeout_usec = DEFAULT_TIMEOUT_USEC,
+                .until_usec = UINT64_MAX,
+                .accept_cached = -1,
+                .push_cache = -1,
+                .echo_mode = _ECHO_MODE_INVALID,
+        };
+        int r;
+
+        assert(link);
+
+        r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
+                return r;
+
+        r = varlink_verify_polkit_async_full(
+                        link,
+                        /* bus= */ NULL,
+                        "io.systemd.ask-password.ask",
+                        /* details= */ NULL,
+                        /* good_user= */ FLAGS_SET(arg_flags, ASK_PASSWORD_USER) ? getuid() : UID_INVALID,
+                        /* flags= */ 0,
+                        polkit_registry);
+        if (r <= 0)
+                return r;
+
+        AskPasswordRequest req = {
+                .tty_fd = -EBADF,
+                .message = p.message ?: arg_message,
+                .icon = p.icon ?: arg_icon,
+                .id = p.id ?: arg_id,
+                .keyring = p.keyring ?: arg_key_name,
+                .credential = arg_credential_name,
+                .hup_fd = sd_varlink_get_input_fd(link),
+        };
+
+        /* Specifying the absolute or relative timeout as zero means: do not ask interactively, only check
+         * cache, hence leave the field at zero in that case. Otherwise we take the minimum of both times. */
+        if (p.timeout_usec != 0 && p.until_usec != 0)
+                req.until = MIN(usec_add(now(CLOCK_MONOTONIC), p.timeout_usec), p.until_usec);
+
+        /* If the timeout is set to zero, don't ask agents, just stick to cache */
+        SET_FLAG(arg_flags, ASK_PASSWORD_NO_AGENT, req.until == 0);
+
+        if (p.accept_cached >= 0)
+                SET_FLAG(arg_flags, ASK_PASSWORD_ACCEPT_CACHED, p.accept_cached);
+
+        if (p.push_cache >= 0)
+                SET_FLAG(arg_flags, ASK_PASSWORD_PUSH_CACHE, p.push_cache);
+
+        if (p.echo_mode >= 0) {
+                SET_FLAG(arg_flags, ASK_PASSWORD_ECHO, p.echo_mode == ECHO_ON);
+                SET_FLAG(arg_flags, ASK_PASSWORD_SILENT, p.echo_mode == ECHO_OFF);
+        }
+
+        _cleanup_strv_free_erase_ char **l = NULL;
+        r = ask_password_auto(&req, arg_flags, &l);
+        if (r == -EUNATCH)
+                return sd_varlink_error(link, "io.systemd.AskPassword.NoPasswordAvailable", NULL);
+        if (r == -ETIME)
+                return sd_varlink_error(link, "io.systemd.AskPassword.TimeoutReached", NULL);
+        if (r == -ECONNRESET) { /* POLLHUP on the varlink fd we passed in via .hup_fd */
+                sd_varlink_close(link);
+                return 1;
+        }
+        if (r < 0)
+                return r;
+
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *vl = NULL;
+        r = sd_json_variant_new_array_strv(&vl, l);
+        if (r < 0)
+                return r;
+
+        sd_json_variant_sensitive(vl);
+
+        return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR("passwords", SD_JSON_BUILD_VARIANT(vl)));
+}
+
+static int vl_server(void) {
+        _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
+        _cleanup_(hashmap_freep) Hashmap *polkit_registry = NULL;
+        int r;
+
+        r = varlink_server_new(&varlink_server, SD_VARLINK_SERVER_INHERIT_USERDATA, /* userdata= */ &polkit_registry);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate Varlink server: %m");
+
+        r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_AskPassword);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add Varlink interface: %m");
+
+        r = sd_varlink_server_bind_method(varlink_server, "io.systemd.AskPassword.Ask", vl_method_ask);
+        if (r < 0)
+                return log_error_errno(r, "Failed to bind Varlink method: %m");
+
+        r = sd_varlink_server_loop_auto(varlink_server);
+        if (r < 0)
+                return log_error_errno(r, "Failed to run Varlink event loop: %m");
+
+        return 0;
+}
+
 static int run(int argc, char *argv[]) {
         _cleanup_strv_free_erase_ char **l = NULL;
         usec_t timeout;
@@ -249,6 +412,9 @@ static int run(int argc, char *argv[]) {
         if (r <= 0)
                 return r;
 
+        if (arg_varlink)
+                return vl_server(); /* Invocation as Varlink service */
+
         timeout = arg_timeout > 0 ? usec_add(now(CLOCK_MONOTONIC), arg_timeout) : 0;
 
         AskPasswordRequest req = {
diff --git a/src/ask-password/io.systemd.ask-password.policy b/src/ask-password/io.systemd.ask-password.policy
new file mode 100644 (file)
index 0000000..8fddf5c
--- /dev/null
@@ -0,0 +1,31 @@
+<?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.ask-password.ask">
+                <description gettext-domain="systemd">Allow to query the user interactively for a password</description>
+                <message gettext-domain="systemd">Authentication is required for an application to ask the user interactively for a password.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+        </action>
+
+</policyconfig>
index af9ef74b329636180eff453ef59aa415ce5b5d4c..213d12d7a8bcd9a5fa3ed77567482b935bf2f7ad 100644 (file)
@@ -177,6 +177,7 @@ shared_sources = files(
         'userdb-dropin.c',
         'userdb.c',
         'varlink-idl-common.c',
+        'varlink-io.systemd.AskPassword.c',
         'varlink-io.systemd.BootControl.c',
         'varlink-io.systemd.Credentials.c',
         'varlink-io.systemd.Hostname.c',
diff --git a/src/shared/varlink-io.systemd.AskPassword.c b/src/shared/varlink-io.systemd.AskPassword.c
new file mode 100644 (file)
index 0000000..86e0a80
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bus-polkit.h"
+#include "varlink-io.systemd.AskPassword.h"
+
+static SD_VARLINK_DEFINE_ENUM_TYPE(
+                EchoMode,
+                SD_VARLINK_FIELD_COMMENT("Request that the password is prompted for without any visual feedback"),
+                SD_VARLINK_DEFINE_ENUM_VALUE(off),
+                SD_VARLINK_FIELD_COMMENT("Show the password in plaintext as it is typed in"),
+                SD_VARLINK_DEFINE_ENUM_VALUE(on),
+                SD_VARLINK_FIELD_COMMENT("Provide visual feedback as the password is typed, but mask the password plaintext"),
+                SD_VARLINK_DEFINE_ENUM_VALUE(masked));
+
+static SD_VARLINK_DEFINE_METHOD(
+                Ask,
+                SD_VARLINK_FIELD_COMMENT("The message to show when prompting for the password"),
+                SD_VARLINK_DEFINE_INPUT(message, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("The name for the kernel keyring entry used for caching"),
+                SD_VARLINK_DEFINE_INPUT(keyname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("The icon name to display, following the freedesktop.org icon naming specification"),
+                SD_VARLINK_DEFINE_INPUT(icon, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("An recognizable id for the password prompt"),
+                SD_VARLINK_DEFINE_INPUT(id, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timeout in µs (relative, CLOCK_MONOTONIC; set to zero to only check cache and not query interactively; set to UINT64_MAX to disable relative timeout; if not set defaults to 90s)"),
+                SD_VARLINK_DEFINE_INPUT(timeoutUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Timeout in µs (absolute, CLOCK_MONOTONIC; if both timeoutUSec and untilUSec are specified the earlier of the two is used; "
+                                         "set to zero to only check cache and not query interactively; leave unset or set to UINT64_NAX to disable absolute timeout)"),
+                SD_VARLINK_DEFINE_INPUT(untilUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Whether to accept cached passwords from the kernel keyring"),
+                SD_VARLINK_DEFINE_INPUT(acceptCached, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Whether to push acquired passwords into the kernel keyring"),
+                SD_VARLINK_DEFINE_INPUT(pushCache, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
+                SD_VARLINK_FIELD_COMMENT("Whether to give visual feedback when typing in the password"),
+                SD_VARLINK_DEFINE_INPUT_BY_TYPE(echo, EchoMode, SD_VARLINK_NULLABLE),
+                VARLINK_DEFINE_POLKIT_INPUT,
+                SD_VARLINK_FIELD_COMMENT("List of acquired passwords. This typically contains one entry, but might contain more in case multiple passwords were previously cached."),
+                SD_VARLINK_DEFINE_OUTPUT(passwords, SD_VARLINK_STRING, SD_VARLINK_ARRAY));
+
+static SD_VARLINK_DEFINE_ERROR(NoPasswordAvailable);
+static SD_VARLINK_DEFINE_ERROR(TimeoutReached);
+
+SD_VARLINK_DEFINE_INTERFACE(
+                io_systemd_AskPassword,
+                "io.systemd.AskPassword",
+                SD_VARLINK_INTERFACE_COMMENT("An interface for interactively asking the user for a password"),
+                SD_VARLINK_SYMBOL_COMMENT("Encodes whether to provide visual feedback as the password is typed in"),
+                &vl_type_EchoMode,
+                SD_VARLINK_SYMBOL_COMMENT("Interactively ask the user for a password, or answer from a previously cached entry"),
+                &vl_method_Ask,
+                SD_VARLINK_SYMBOL_COMMENT("No password available, because none was provided in the cache, and no agent was asked"),
+                &vl_error_NoPasswordAvailable,
+                SD_VARLINK_SYMBOL_COMMENT("Query timeout reached, user did not provide a password in time"),
+                &vl_error_TimeoutReached);
diff --git a/src/shared/varlink-io.systemd.AskPassword.h b/src/shared/varlink-io.systemd.AskPassword.h
new file mode 100644 (file)
index 0000000..1be83f4
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "sd-varlink-idl.h"
+
+extern const sd_varlink_interface vl_interface_io_systemd_AskPassword;
index 182d59bd2063f41457e98add06182a24644c4933..74c64d392abd2f4e337831f7c6e17ec51b67ad91 100644 (file)
@@ -11,6 +11,7 @@
 #include "varlink-idl-util.h"
 #include "varlink-io.systemd.h"
 #include "varlink-io.systemd.BootControl.h"
+#include "varlink-io.systemd.AskPassword.h"
 #include "varlink-io.systemd.Credentials.h"
 #include "varlink-io.systemd.Import.h"
 #include "varlink-io.systemd.Journal.h"
@@ -194,6 +195,8 @@ TEST(parse_format) {
         print_separator();
         test_parse_format_one(&vl_interface_io_systemd_MachineImage);
         print_separator();
+        test_parse_format_one(&vl_interface_io_systemd_AskPassword);
+        print_separator();
         test_parse_format_one(&vl_interface_xyz_test);
 }
 
index 00978a18b00b40445159a6846ffd0933384b70db..f6d661da9751c0816c34e6b758b3a0962432f48b 100644 (file)
@@ -245,6 +245,11 @@ units = [
         { 'file' : 'system-update-cleanup.service' },
         { 'file' : 'system-update-pre.target' },
         { 'file' : 'system-update.target' },
+        {
+          'file' : 'systemd-ask-password.socket',
+          'symlinks' : ['sockets.target.wants/']
+        },
+        { 'file' : 'systemd-ask-password@.service' },
         {
           'file' : 'systemd-ask-password-console.path',
           'symlinks' : ['sysinit.target.wants/'],
diff --git a/units/systemd-ask-password.socket b/units/systemd-ask-password.socket
new file mode 100644 (file)
index 0000000..c8d203b
--- /dev/null
@@ -0,0 +1,21 @@
+#  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.
+
+[Unit]
+Description=Query the User Interactively for a Password
+Documentation=man:systemd-ask-password(1)
+DefaultDependencies=no
+Before=sockets.target
+
+[Socket]
+ListenStream=/run/systemd/io.systemd.AskPassword
+FileDescriptorName=varlink
+SocketMode=0666
+Accept=yes
+MaxConnectionsPerSource=16
diff --git a/units/systemd-ask-password@.service b/units/systemd-ask-password@.service
new file mode 100644 (file)
index 0000000..07bbd45
--- /dev/null
@@ -0,0 +1,16 @@
+#  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.
+
+[Unit]
+Description=Query the User Interactively for a Password
+Documentation=man:systemd-ask-password(1)
+DefaultDependencies=no
+
+[Service]
+ExecStart=-systemd-ask-password --system --no-tty
index 21070f7ef85d81f465d3b545e6d31314e43f7591..290f268ef1de5901ee4dfeac78cd171b8392125a 100644 (file)
@@ -1,34 +1,64 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 units = [
-        'app.slice',
-        'background.slice',
-        'basic.target',
-        'bluetooth.target',
-        'capsule@.target',
-        'default.target',
-        'exit.target',
-        'graphical-session-pre.target',
-        'graphical-session.target',
-        'paths.target',
-        'printer.target',
-        'session.slice',
-        'shutdown.target',
-        'smartcard.target',
-        'sockets.target',
-        'sound.target',
-        'systemd-exit.service',
-        'systemd-tmpfiles-clean.service',
-        'systemd-tmpfiles-clean.timer',
-        'systemd-tmpfiles-setup.service',
-        'timers.target',
+        { 'file' : 'app.slice' },
+        { 'file' : 'background.slice' },
+        { 'file' : 'basic.target' },
+        { 'file' : 'bluetooth.target' },
+        { 'file' : 'capsule@.target' },
+        { 'file' : 'default.target' },
+        { 'file' : 'exit.target' },
+        { 'file' : 'graphical-session-pre.target' },
+        { 'file' : 'graphical-session.target' },
+        { 'file' : 'paths.target' },
+        { 'file' : 'printer.target' },
+        { 'file' : 'session.slice' },
+        { 'file' : 'shutdown.target' },
+        { 'file' : 'smartcard.target' },
+        { 'file' : 'sockets.target' },
+        { 'file' : 'sound.target' },
+        {
+          'file' : 'systemd-ask-password.socket',
+          'symlinks' : ['sockets.target.wants/']
+        },
+        { 'file' : 'systemd-ask-password@.service' },
+        { 'file' : 'systemd-exit.service' },
+        { 'file' : 'systemd-tmpfiles-clean.service' },
+        { 'file' : 'systemd-tmpfiles-clean.timer' },
+        { 'file' : 'systemd-tmpfiles-setup.service' },
+        { 'file' : 'timers.target' },
+        {
+          'file' : 'xdg-desktop-autostart.target',
+          'conditions': ['ENABLE_XDG_AUTOSTART'],
+        }
 ]
 
-if conf.get('ENABLE_XDG_AUTOSTART') == 1
-        units += 'xdg-desktop-autostart.target'
-endif
+foreach unit : units
+        file = unit.get('file')
 
-foreach file : units
-        install_data(file,
-                     install_dir : userunitdir)
+        install = true
+        foreach cond : unit.get('conditions', [])
+                if conf.get(cond) != 1
+                        install = false
+                        break
+                endif
+        endforeach
+
+        if install
+                install_data(file,
+                             install_dir : userunitdir)
+
+                foreach target : unit.get('symlinks', [])
+                        if target.endswith('/')
+                                install_emptydir(userunitdir / target)
+                                meson.add_install_script(sh, '-c',
+                                                         ln_s.format(userunitdir / file,
+                                                                     userunitdir / target / file))
+                        else
+                                meson.add_install_script(sh, '-c',
+                                                         ln_s.format(userunitdir / file,
+                                                                     userunitdir / target))
+                        endif
+                endforeach
+        endif
 endforeach
diff --git a/units/user/systemd-ask-password.socket b/units/user/systemd-ask-password.socket
new file mode 100644 (file)
index 0000000..ce9ccd9
--- /dev/null
@@ -0,0 +1,20 @@
+#  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.
+
+[Unit]
+Description=Query the User Interactively for a Password
+Documentation=man:systemd-ask-password(1)
+DefaultDependencies=no
+Before=sockets.target
+
+[Socket]
+ListenStream=%t/systemd/io.systemd.AskPassword
+FileDescriptorName=varlink
+SocketMode=0600
+Accept=yes
diff --git a/units/user/systemd-ask-password@.service b/units/user/systemd-ask-password@.service
new file mode 100644 (file)
index 0000000..e5d72ff
--- /dev/null
@@ -0,0 +1,16 @@
+#  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.
+
+[Unit]
+Description=Query the User Interactively for a Password
+Documentation=man:systemd-ask-password(1)
+DefaultDependencies=no
+
+[Service]
+ExecStart=-systemd-ask-password --user --no-tty