]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
exec-invoke: respect $HOME set via PAM
authorLennart Poettering <lennart@poettering.net>
Fri, 24 Jan 2025 10:17:55 +0000 (11:17 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 6 Feb 2025 08:23:49 +0000 (09:23 +0100)
This follows the same recent change in util-linux:

https://github.com/util-linux/util-linux/pull/3354

i.e. we generally want that PAM modules can override $HOME and it is
honoured for the CWD after login.

(This renames the 'home' variable we maintained sofar to 'pwent_home',
to clarify that it's the home directory listed in the struct passwd
entry, and thus not necessarily the one actually used)

src/core/exec-invoke.c

index 24e700a28927bf97a20e820c215c20ad2ddfdc35..265fe648a6ee31d831e55acab21003dc93a45728 100644 (file)
@@ -3619,7 +3619,8 @@ static int apply_working_directory(
                 const ExecContext *context,
                 const ExecParameters *params,
                 ExecRuntime *runtime,
-                const char *home) {
+                const char *pwent_home,
+                const char *const *env) {
 
         const char *wd;
         int r;
@@ -3627,10 +3628,15 @@ static int apply_working_directory(
         assert(context);
 
         if (context->working_directory_home) {
-                if (!home)
-                        return -ENXIO;
-
-                wd = home;
+                /* Preferably use the data from $HOME, in case it was updated by a PAM module */
+                wd = strv_env_get((char**) env, "HOME");
+                if (!wd) {
+                        /* If that's not available, use the data from the struct passwd entry: */
+                        if (!pwent_home)
+                                return -ENXIO;
+
+                        wd = pwent_home;
+                }
         } else
                 wd = empty_to_root(context->working_directory);
 
@@ -4393,7 +4399,7 @@ int exec_invoke(
         _cleanup_free_ gid_t *supplementary_gids = NULL;
         const char *username = NULL, *groupname = NULL;
         _cleanup_free_ char *home_buffer = NULL, *memory_pressure_path = NULL, *own_user = NULL;
-        const char *home = NULL, *shell = NULL;
+        const char *pwent_home = NULL, *shell = NULL;
         char **final_argv = NULL;
         dev_t journal_stream_dev = 0;
         ino_t journal_stream_ino = 0;
@@ -4645,7 +4651,7 @@ int exec_invoke(
                         u = NULL;
 
                 if (u) {
-                        r = get_fixed_user(u, &username, &uid, &gid, &home, &shell);
+                        r = get_fixed_user(u, &username, &uid, &gid, &pwent_home, &shell);
                         if (r < 0) {
                                 *exit_status = EXIT_USER;
                                 return log_exec_error_errno(context, params, r, "Failed to determine user credentials: %m");
@@ -4677,7 +4683,7 @@ int exec_invoke(
 
         params->user_lookup_fd = safe_close(params->user_lookup_fd);
 
-        r = acquire_home(context, &home, &home_buffer);
+        r = acquire_home(context, &pwent_home, &home_buffer);
         if (r < 0) {
                 *exit_status = EXIT_CHDIR;
                 return log_exec_error_errno(context, params, r, "Failed to determine $HOME for the invoking user: %m");
@@ -4983,7 +4989,7 @@ int exec_invoke(
                         params,
                         cgroup_context,
                         n_fds,
-                        home,
+                        pwent_home,
                         username,
                         shell,
                         journal_stream_dev,
@@ -5505,7 +5511,7 @@ int exec_invoke(
          * running this service might have the correct privilege to change to the working directory. Also, it
          * is absolutely ðŸ’£ crucial ðŸ’£ we applied all mount namespacing rearrangements before this, so that
          * the cwd cannot be used to pin directories outside of the sandbox. */
-        r = apply_working_directory(context, params, runtime, home);
+        r = apply_working_directory(context, params, runtime, pwent_home, (const char* const*) accum_env);
         if (r < 0) {
                 *exit_status = EXIT_CHDIR;
                 return log_exec_error_errno(context, params, r, "Changing to the requested working directory failed: %m");