]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shell: define three system credentials we can propagate into shell prompts and welcom...
authorLennart Poettering <lennart@poettering.net>
Fri, 6 Sep 2024 14:30:54 +0000 (16:30 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 9 Sep 2024 17:03:48 +0000 (19:03 +0200)
14 files changed:
TODO
man/pam_systemd.xml
man/systemd.system-credentials.xml
meson.build
meson_options.txt
profile.d/70-systemd-shell-extra.sh [new file with mode: 0644]
profile.d/meson.build [new file with mode: 0644]
src/login/pam_systemd.c
tmpfiles.d/20-systemd-shell-extra.conf.in [new file with mode: 0644]
tmpfiles.d/meson.build
units/console-getty.service.in
units/container-getty@.service.in
units/getty@.service.in
units/serial-getty@.service.in

diff --git a/TODO b/TODO
index d2eeed503f0e4f994a7d6f9004e56196fc5ec15c..83bce330d7616f32ea4c208bce0e7804978f5612 100644 (file)
--- a/TODO
+++ b/TODO
@@ -130,14 +130,8 @@ Deprecations and removals:
 
 Features:
 
-* introduce a new system credential "shell.prompt.extra" or so that may contain
-  a string to include in $PS1. Inherit it down into gettys/logins and suchlike.
-  And provide an /etc/profile.d/*.sh drop-in which reads the credential if set,
-  and suffixes $PS1. Usecase: for wsl-like environments use this to include
-  additional information in prompts that is inherited from the execution
-  context. For example include 📦 emoji via this mechanism in the prompt. Or,
-  in run0 include a ☢️  emoji in the prompt. Or in mkosi include a 👷 emoji in
-  the prompt. You get the idea.
+* maybe set shell.prompt.prefix credential in run0 to some warning emoji,
+  i.e. ⚠️ or ☢️ or ⚡ or 👊 or 🧑‍🔧 or so.
 
 * introduce new structure Tpm2CombinedPolicy, that combines the various TPm2
   policy bits into one structure, i.e. public key info, pcr masks, pcrlock
index 40a4564a22c48283b352900342d72c6260141861..c55cdee894a23eaa75eb743d083043bf509313e1 100644 (file)
         <xi:include href="version-info.xml" xpointer="v245"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>$SHELL_PROMPT_PREFIX</varname></term>
+        <term><varname>$SHELL_PROMPT_SUFFIX</varname></term>
+        <term><varname>$SHELL_WELCOME</varname></term>
+
+        <listitem><para>These environment variables are initialized from the service credentials
+        <literal>shell.prompt.prefix</literal>, <literal>shell.prompt.suffix</literal> and
+        <literal>shell.welcome</literal> if set. They are passed to the invoked session processes, where they
+        are imported into any shell prompt (specifically <varname>$SHELL_PROMPT_PREFIX</varname> is added as
+        prefix to <varname>$PS1</varname>, and <varname>$SHELL_PROMPT_SUFFIX</varname> as suffix) or printed
+        on screen when a shell first initializes.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
+
     </variablelist>
 
     <para>The following environment variables are read by the module and may be used by the PAM service to pass
index f8c27d04acc300864a7122ae87b175619008e866..7962bb257ab305b012c5ff95d651d184e698ef0a 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>shell.prompt.prefix</varname></term>
+        <term><varname>shell.prompt.suffix</varname></term>
+        <listitem>
+          <para>Defines strings to prefix and suffix any interactive UNIX shell prompt with. For details see
+          <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+          <xi:include href="version-info.xml" xpointer="v257"/>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>shell.welcome</varname></term>
+        <listitem>
+          <para>Define a string to print when an interactive UNIX shell initializes. For details see
+          <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+          <xi:include href="version-info.xml" xpointer="v257"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>system.machine_id</varname></term>
         <listitem>
index c26302d25cacbe6016986ab6150252b0ffca83d6..80e0047281b3d849bc15f50fb5807e26d2316d66 100644 (file)
@@ -188,7 +188,7 @@ mimepackagesdir = prefixdir / 'share/mime/packages'
 
 configfiledir = get_option('configfiledir')
 if configfiledir == ''
-        configfiledir= sysconfdir
+        configfiledir = sysconfdir
 endif
 pkgconfigfiledir = configfiledir / 'systemd'
 
@@ -228,6 +228,13 @@ if libcryptsetup_plugins_dir == ''
         libcryptsetup_plugins_dir = libdir / 'cryptsetup'
 endif
 
+shellprofiledir = get_option('shellprofiledir')
+if shellprofiledir == ''
+        shellprofiledir = sysconfdir / 'profile.d'
+endif
+conf.set10('LINK_SHELL_EXTRA_DROPIN', shellprofiledir != 'no' and not shellprofiledir.startswith('/usr/'))
+conf.set('SHELLPROFILEDIR', shellprofiledir, description : 'shell profile directory')
+
 memory_accounting_default = get_option('memory-accounting-default')
 status_unit_format_default = get_option('status-unit-format-default')
 if status_unit_format_default == 'auto'
@@ -257,6 +264,7 @@ conf.set_quoted('RANDOM_SEED_DIR',                            randomseeddir)
 conf.set_quoted('RC_LOCAL_PATH',                              get_option('rc-local'))
 conf.set_quoted('SSHCONFDIR',                                 sshconfdir)
 conf.set_quoted('SSHDCONFDIR',                                sshdconfdir)
+conf.set_quoted('SHELLPROFILEDIR',                            shellprofiledir)
 conf.set_quoted('SYSCONF_DIR',                                sysconfdir)
 conf.set_quoted('SYSCTL_DIR',                                 sysctldir)
 conf.set_quoted('SYSTEMCTL_BINARY_PATH',                      bindir / 'systemctl')
@@ -2701,6 +2709,7 @@ subdir('man')
 subdir('modprobe.d')
 subdir('network')
 subdir('presets')
+subdir('profile.d')
 subdir('shell-completion/bash')
 subdir('shell-completion/zsh')
 subdir('sysctl.d')
@@ -2923,6 +2932,7 @@ summary({
         'ssh server privilege separation directory' : sshdprivsepdir,
         'ssh client configuration directory' : sshconfdir,
         'libcryptsetup plugins directory' : libcryptsetup_plugins_dir,
+        'Shell profile directory' :         shellprofiledir,
         'RPM macros directory' :            rpmmacrosdir,
         'modprobe.d directory' :            modprobedir,
         'D-Bus policy directory' :          dbuspolicydir,
index 185aa85a8deb7f59ee652dd629856790a3fd783f..e90debdd3e01e636fcceb29aedb00c29b74cb546 100644 (file)
@@ -225,6 +225,8 @@ option('sshdprivsepdir', type : 'string',
        description : 'directory for SSH privilege separation ["no" disables]', value : '/run/sshd')
 option('libcryptsetup-plugins-dir', type : 'string',
        description : 'directory for libcryptsetup plugins')
+option('shellprofiledir', type : 'string',
+       description : 'directory for Shell profile drop-ins ["no" disables]')
 option('docdir', type : 'string',
        description : 'documentation directory')
 option('install-sysconfdir', type : 'combo', choices : ['true', 'no-samples', 'false'], value : 'true',
diff --git a/profile.d/70-systemd-shell-extra.sh b/profile.d/70-systemd-shell-extra.sh
new file mode 100644 (file)
index 0000000..70be334
--- /dev/null
@@ -0,0 +1,25 @@
+# shellcheck shell=sh
+
+#  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.
+
+# Import the additional shell prompt prefix and suffix strings into $PS1, and
+# show the shell welcome string. These can be provisioned as system or service
+# credentials shell.prompt.prefix, shell.prompt.suffix and shell.welcome, and
+# are propagated into these environment variables by pam_systemd(8).
+
+if [ -n "$SHELL_PROMPT_PREFIX" ]; then
+    PS1="$SHELL_PROMPT_PREFIX$PS1"
+fi
+
+if [ -n "$SHELL_PROMPT_SUFFIX" ]; then
+    PS1="$PS1$SHELL_PROMPT_SUFFIX"
+fi
+
+if [ -n "$SHELL_WELCOME" ]; then
+   printf '%b\n' "$SHELL_WELCOME"
+fi
diff --git a/profile.d/meson.build b/profile.d/meson.build
new file mode 100644 (file)
index 0000000..b87dc18
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+install_data('70-systemd-shell-extra.sh', install_dir : shellprofiledir.startswith('/usr/') ? shellprofiledir : libexecdir / 'profile.d')
+
+if conf.get('LINK_SHELL_EXTRA_DROPIN') == 1
+        install_emptydir(shellprofiledir)
+
+        meson.add_install_script(sh, '-c',
+                ln_s.format(libexecdir / 'profile.d' / '70-systemd-shell-extra.sh', shellprofiledir / '70-systemd-shell-extra.sh'))
+endif
index 40721ebfd9f1529c34916d6aa2b5d499a8a6eeff..77b23d54dbd1122f83103be2a31e629cd32623d4 100644 (file)
@@ -27,6 +27,7 @@
 #include "cap-list.h"
 #include "capability-util.h"
 #include "cgroup-setup.h"
+#include "creds-util.h"
 #include "devnum-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
@@ -567,6 +568,31 @@ static int update_environment(pam_handle_t *handle, const char *key, const char
         return PAM_SUCCESS;
 }
 
+static int propagate_credential_to_environment(pam_handle_t *handle, const char *credential, const char *varname) {
+        int r;
+
+        assert(handle);
+        assert(credential);
+        assert(varname);
+
+        _cleanup_free_ char *value = NULL;
+
+        /* Read a service credential, and propagate it into an environment variable */
+
+        r = read_credential(credential, (void**) &value, /* ret_size= */ NULL);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to read credential '%s', ignoring: %m", credential);
+                return PAM_SUCCESS;
+        }
+
+        r = pam_misc_setenv(handle, varname, value, 0);
+        if (r != PAM_SUCCESS)
+                return pam_syslog_pam_error(handle, LOG_ERR, r,
+                                            "Failed to set environment variable %s: @PAMERR@", varname);
+
+        return PAM_SUCCESS;
+}
+
 static bool validate_runtime_directory(pam_handle_t *handle, const char *path, uid_t uid) {
         struct stat st;
 
@@ -1192,6 +1218,19 @@ _public_ PAM_EXTERN int pam_sm_open_session(
         if (r != PAM_SUCCESS)
                 return r;
 
+        static const char *const propagate[] = {
+                "shell.prompt.prefix", "SHELL_PROMPT_PREFIX",
+                "shell.prompt.suffix", "SHELL_PROMPT_SUFFIX",
+                "shell.welcome",       "SHELL_WELCOME",
+                NULL
+        };
+
+        STRV_FOREACH_PAIR(k, v, propagate) {
+                r = propagate_credential_to_environment(handle, *k, *v);
+                if (r != PAM_SUCCESS)
+                        return r;
+        }
+
         if (vtnr > 0) {
                 char buf[DECIMAL_STR_MAX(vtnr)];
                 sprintf(buf, "%u", vtnr);
diff --git a/tmpfiles.d/20-systemd-shell-extra.conf.in b/tmpfiles.d/20-systemd-shell-extra.conf.in
new file mode 100644 (file)
index 0000000..8ebe83d
--- /dev/null
@@ -0,0 +1,12 @@
+#  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.
+
+# See tmpfiles.d(5) for details
+
+{% if LINK_SHELL_EXTRA_DROPIN %}
+L {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
+{% endif %}
index bec24ac7b4db119a5db9eee6eb2aca55bd641b96..8d05abcfc143da7fbe7d40cf24efe61dc75145c1 100644 (file)
@@ -36,6 +36,7 @@ in_files = [['etc.conf',                      ''],
             ['var.conf',                      ''],
             ['20-systemd-userdb.conf',        'ENABLE_SSH_USERDB_CONFIG'],
             ['20-systemd-ssh-generator.conf', 'ENABLE_SSH_PROXY_CONFIG'],
+            ['20-systemd-shell-extra.conf',   'LINK_SHELL_EXTRA_DROPIN'],
            ]
 
 foreach pair : in_files
index 575a7770c9dbdbe6147cd926f2f3826606c81c6d..33e6368db15d31b6f6dc94f8e92ead7c7b06d6b2 100644 (file)
@@ -40,6 +40,7 @@ ImportCredential=tty.console.agetty.*:agetty.
 ImportCredential=tty.console.login.*:login.
 ImportCredential=agetty.*
 ImportCredential=login.*
+ImportCredential=shell.*
 
 [Install]
 WantedBy=getty.target
index 6bee309bf5a5a76113bb667e29a9231c8285ab7b..7573532d6ddbafbc4fdb96675f24d592e03794be 100644 (file)
@@ -46,3 +46,4 @@ ImportCredential=tty.container.%I.agetty.*:agetty.
 ImportCredential=tty.container.%I.login.*:login.
 ImportCredential=agetty.*
 ImportCredential=login.*
+ImportCredential=shell.*
index 3ea95e1ee4fd0dc1562dbd97f9b3bdea379e3e95..f30bba406d5a11798e5b8263189d36d3986944dd 100644 (file)
@@ -56,6 +56,7 @@ ImportCredential=tty.virtual.%I.agetty.*:agetty.
 ImportCredential=tty.virtual.%I.login.*:login.
 ImportCredential=agetty.*
 ImportCredential=login.*
+ImportCredential=shell.*
 
 # Unset locale for the console getty since the console has problems
 # displaying some internationalized messages.
index a071241ef90d6df8c488bba4f73fd5917003b633..20a5eb2754f58cc23ac28e69628a77ef47f7f34a 100644 (file)
@@ -50,6 +50,7 @@ ImportCredential=tty.serial.%I.agetty.*:agetty.
 ImportCredential=tty.serial.%I.login.*:login.
 ImportCredential=agetty.*
 ImportCredential=login.*
+ImportCredential=shell.*
 
 [Install]
 WantedBy=getty.target