65878a
From 553a962a570cade5c44953593209d25e28ec5145 Mon Sep 17 00:00:00 2001
65878a
From: Michal Sekletar <msekleta@redhat.com>
65878a
Date: Mon, 3 Mar 2014 15:37:49 +0100
65878a
Subject: [PATCH] logind: rework session shutdown logic
65878a
65878a
Simplify the shutdown logic a bit:
65878a
65878a
- Keep the session FIFO around in the PAM module, even after the session
65878a
  shutdown hook has been finished. This allows logind to track precisely
65878a
  when the PAM handler goes away.
65878a
65878a
- In the ReleaseSession() call start a timer, that will stop terminate
65878a
  the session when elapsed.
65878a
65878a
- Never fiddle with the KillMode of scopes to configure whether user
65878a
  processes should be killed or not. Instead, simply leave the scope
65878a
  units around when we terminate a session whose processes should not be
65878a
  killed.
65878a
65878a
- When killing is enabled, stop the session scope on FIFO EOF or after
65878a
  the ReleaseSession() timeout. When killing is disabled, simply tell
65878a
  PID 1 to abandon the scope.
65878a
65878a
Because the scopes stay around and hence all processes are always member
65878a
of a scope, the system shutdown logic should be more robust, as the
65878a
scopes can be shutdown as part of the usual shutdown logic.
65878a
65878a
Based-on: 5f41d1f10fd97e93517b6a762b1bec247f4d1171
65878a
---
65878a
 src/login/logind-dbus.c    |  51 +++++++++++-------
65878a
 src/login/logind-session.c | 130 +++++++++++++++++++++++++++++++++++----------
65878a
 src/login/logind-session.h |   4 ++
65878a
 src/login/logind-user.c    |  23 +++++---
65878a
 src/login/logind-user.h    |   1 +
65878a
 src/login/logind.c         |  23 ++++++--
65878a
 src/login/logind.h         |   4 +-
65878a
 src/login/pam-module.c     |  11 ++--
65878a
 8 files changed, 182 insertions(+), 65 deletions(-)
65878a
65878a
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
65878a
index 69e94aa..8de301e 100644
65878a
--- a/src/login/logind-dbus.c
65878a
+++ b/src/login/logind-dbus.c
65878a
@@ -1747,13 +1747,7 @@ static DBusHandlerResult manager_message_handler(
65878a
                 if (!session)
65878a
                         return bus_send_error_reply(connection, message, &error, -ENOENT);
65878a
 
65878a
-                /* We use the FIFO to detect stray sessions where the
65878a
-                process invoking PAM dies abnormally. We need to make
65878a
-                sure that that process is not killed if at the clean
65878a
-                end of the session it closes the FIFO. Hence, with
65878a
-                this call explicitly turn off the FIFO logic, so that
65878a
-                the PAM code can finish clean up on its own */
65878a
-                session_remove_fifo(session);
65878a
+                session_release(session);
65878a
 
65878a
                 reply = dbus_message_new_method_return(message);
65878a
                 if (!reply)
65878a
@@ -2551,7 +2545,6 @@ int manager_start_scope(
65878a
                 const char *slice,
65878a
                 const char *description,
65878a
                 const char *after,
65878a
-                const char *kill_mode,
65878a
                 DBusError *error,
65878a
                 char **job) {
65878a
 
65878a
@@ -2623,18 +2616,6 @@ int manager_start_scope(
65878a
                         return log_oom();
65878a
         }
65878a
 
65878a
-        if (!isempty(kill_mode)) {
65878a
-                const char *kill_mode_property = "KillMode";
65878a
-
65878a
-                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
65878a
-                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
65878a
-                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
65878a
-                    !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
65878a
-                    !dbus_message_iter_close_container(&sub2, &sub3) ||
65878a
-                    !dbus_message_iter_close_container(&sub, &sub2))
65878a
-                        return log_oom();
65878a
-        }
65878a
-
65878a
         /* cgroup empty notification is not available in containers
65878a
          * currently. To make this less problematic, let's shorten the
65878a
          * stop timeout for sessions, so that we don't wait
65878a
@@ -2793,6 +2774,36 @@ int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char
65878a
         return 1;
65878a
 }
65878a
 
65878a
+int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error) {
65878a
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
65878a
+        _cleanup_free_ char *path = NULL;
65878a
+        int r;
65878a
+
65878a
+        assert(manager);
65878a
+        assert(scope);
65878a
+
65878a
+        path = unit_dbus_path_from_name(scope);
65878a
+        if (!path)
65878a
+                return -ENOMEM;
65878a
+
65878a
+        r = bus_method_call_with_reply(
65878a
+                manager->bus,
65878a
+                "org.freedesktop.systemd1",
65878a
+                path,
65878a
+                "org.freedesktop.systemd1.Scope",
65878a
+                "Abandon",
65878a
+                &reply,
65878a
+                error,
65878a
+                DBUS_TYPE_INVALID);
65878a
+
65878a
+        if (r < 0) {
65878a
+                log_error("Failed to abandon scope %s", scope);
65878a
+                return r;
65878a
+        }
65878a
+
65878a
+        return 1;
65878a
+}
65878a
+
65878a
 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
65878a
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
65878a
         const char *w;
65878a
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
65878a
index 27aa335..78e6d74 100644
65878a
--- a/src/login/logind-session.c
65878a
+++ b/src/login/logind-session.c
65878a
@@ -24,6 +24,7 @@
65878a
 #include <unistd.h>
65878a
 #include <sys/epoll.h>
65878a
 #include <fcntl.h>
65878a
+#include <sys/timerfd.h>
65878a
 
65878a
 #include <systemd/sd-id128.h>
65878a
 #include <systemd/sd-messages.h>
65878a
@@ -36,6 +37,8 @@
65878a
 #include "dbus-common.h"
65878a
 #include "logind-session.h"
65878a
 
65878a
+#define RELEASE_SEC 20
65878a
+
65878a
 static unsigned devt_hash_func(const void *p) {
65878a
         uint64_t u = *(const dev_t*)p;
65878a
 
65878a
@@ -505,7 +508,6 @@ static int session_start_scope(Session *s) {
65878a
 
65878a
         if (!s->scope) {
65878a
                 _cleanup_free_ char *description = NULL;
65878a
-                const char *kill_mode;
65878a
                 char *scope, *job;
65878a
 
65878a
                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
65878a
@@ -516,9 +518,7 @@ static int session_start_scope(Session *s) {
65878a
                 if (!scope)
65878a
                         return log_oom();
65878a
 
65878a
-                kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
65878a
-
65878a
-                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job;;
65878a
+                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", &error, &job;;
65878a
                 if (r < 0) {
65878a
                         log_error("Failed to start session scope %s: %s %s",
65878a
                                   scope, bus_error(&error, r), error.name);
65878a
@@ -579,23 +579,22 @@ int session_start(Session *s) {
65878a
 
65878a
         s->started = true;
65878a
 
65878a
-        /* Save session data */
65878a
+        /* Save data */
65878a
         session_save(s);
65878a
         user_save(s->user);
65878a
+        if (s->seat)
65878a
+                seat_save(s->seat);
65878a
 
65878a
+        /* Send signals */
65878a
         session_send_signal(s, true);
65878a
 
65878a
         if (s->seat) {
65878a
-                seat_save(s->seat);
65878a
-
65878a
                 if (s->seat->active == s)
65878a
                         seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
65878a
                 else
65878a
                         seat_send_changed(s->seat, "Sessions\0");
65878a
         }
65878a
 
65878a
-        user_send_changed(s->user, "Sessions\0");
65878a
-
65878a
         return 0;
65878a
 }
65878a
 
65878a
@@ -611,15 +610,24 @@ static int session_stop_scope(Session *s) {
65878a
         if (!s->scope)
65878a
                 return 0;
65878a
 
65878a
-        r = manager_stop_unit(s->manager, s->scope, &error, &job;;
65878a
-        if (r < 0) {
65878a
-                log_error("Failed to stop session scope: %s", bus_error(&error, r));
65878a
-                dbus_error_free(&error);
65878a
-                return r;
65878a
-        }
65878a
+        if (manager_shall_kill(s->manager, s->user->name)) {
65878a
+                r = manager_stop_unit(s->manager, s->scope, &error, &job;;
65878a
+                if (r < 0) {
65878a
+                        log_error("Failed to stop session scope: %s", bus_error(&error, r));
65878a
+                        dbus_error_free(&error);
65878a
+                        return r;
65878a
+                }
65878a
 
65878a
-        free(s->scope_job);
65878a
-        s->scope_job = job;
65878a
+                free(s->scope_job);
65878a
+                s->scope_job = job;
65878a
+        } else {
65878a
+                r = manager_abandon_scope(s->manager, s->scope, &error);
65878a
+                if (r < 0) {
65878a
+                        log_error("Failed to abandon session scope: %s", bus_error(&error, r));
65878a
+                        dbus_error_free(&error);
65878a
+                        return r;
65878a
+                }
65878a
+        }
65878a
 
65878a
         return 0;
65878a
 }
65878a
@@ -644,6 +652,19 @@ static int session_unlink_x11_socket(Session *s) {
65878a
         return r < 0 ? -errno : 0;
65878a
 }
65878a
 
65878a
+static void session_close_timer_fd(Session *s) {
65878a
+        assert(s);
65878a
+
65878a
+        if (s->timer_fd <= 0)
65878a
+                return;
65878a
+
65878a
+        hashmap_remove(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1));
65878a
+        epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->timer_fd, NULL);
65878a
+
65878a
+        close_nointr(s->timer_fd);
65878a
+        s->timer_fd = -1;
65878a
+}
65878a
+
65878a
 int session_stop(Session *s) {
65878a
         int r;
65878a
 
65878a
@@ -652,11 +673,18 @@ int session_stop(Session *s) {
65878a
         if (!s->user)
65878a
                 return -ESTALE;
65878a
 
65878a
+        session_close_timer_fd(s);
65878a
+
65878a
+        /* We are going down, don't care about FIFOs anymore */
65878a
+        session_remove_fifo(s);
65878a
+
65878a
         /* Kill cgroup */
65878a
         r = session_stop_scope(s);
65878a
 
65878a
         session_save(s);
65878a
 
65878a
+        s->stopping = true;
65878a
+
65878a
         return r;
65878a
 }
65878a
 
65878a
@@ -678,6 +706,8 @@ int session_finalize(Session *s) {
65878a
                            "MESSAGE=Removed session %s.", s->id,
65878a
                            NULL);
65878a
 
65878a
+        session_close_timer_fd(s);
65878a
+
65878a
         /* Kill session devices */
65878a
         while ((sd = hashmap_first(s->devices)))
65878a
                 session_device_free(sd);
65878a
@@ -698,16 +728,64 @@ int session_finalize(Session *s) {
65878a
                 if (s->seat->active == s)
65878a
                         seat_set_active(s->seat, NULL);
65878a
 
65878a
-                seat_send_changed(s->seat, "Sessions\0");
65878a
                 seat_save(s->seat);
65878a
+                seat_send_changed(s->seat, "Sessions\0");
65878a
         }
65878a
 
65878a
-        user_send_changed(s->user, "Sessions\0");
65878a
         user_save(s->user);
65878a
+        user_send_changed(s->user, "Sessions\0");
65878a
 
65878a
         return r;
65878a
 }
65878a
 
65878a
+void session_release(Session *s) {
65878a
+        int r;
65878a
+
65878a
+        struct itimerspec its = { .it_value.tv_sec = RELEASE_SEC };
65878a
+        struct epoll_event ev = {};
65878a
+
65878a
+        assert(s);
65878a
+
65878a
+        if (!s->started || s->stopping)
65878a
+                return;
65878a
+
65878a
+        if (s->timer_fd >= 0)
65878a
+                return;
65878a
+
65878a
+        s->timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
65878a
+        if (s->timer_fd < 0) {
65878a
+                log_error("Failed to create session release timer fd");
65878a
+                goto out;
65878a
+        }
65878a
+
65878a
+        r = hashmap_put(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1), s);
65878a
+        if (r < 0) {
65878a
+                log_error("Failed to store session release timer fd");
65878a
+                goto out;
65878a
+        }
65878a
+
65878a
+        ev.events = EPOLLONESHOT;
65878a
+        ev.data.u32 = FD_OTHER_BASE + s->timer_fd;
65878a
+
65878a
+        r = epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->timer_fd, &ev;;
65878a
+        if (r < 0) {
65878a
+                log_error("Failed to add session release timer fd to epoll instance");
65878a
+                goto out;
65878a
+        }
65878a
+
65878a
+        r = timerfd_settime(s->timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
65878a
+        if (r < 0) {
65878a
+                log_error("Failed to arm timer : %m");
65878a
+                goto out;
65878a
+        }
65878a
+
65878a
+out:
65878a
+        if (s->timer_fd >= 0) {
65878a
+                close_nointr(s->timer_fd);
65878a
+                s->timer_fd = -1;
65878a
+        }
65878a
+}
65878a
+
65878a
 bool session_is_active(Session *s) {
65878a
         assert(s);
65878a
 
65878a
@@ -904,8 +982,6 @@ void session_remove_fifo(Session *s) {
65878a
 }
65878a
 
65878a
 int session_check_gc(Session *s, bool drop_not_started) {
65878a
-        int r;
65878a
-
65878a
         assert(s);
65878a
 
65878a
         if (drop_not_started && !s->started)
65878a
@@ -915,11 +991,7 @@ int session_check_gc(Session *s, bool drop_not_started) {
65878a
                 return 0;
65878a
 
65878a
         if (s->fifo_fd >= 0) {
65878a
-                r = pipe_eof(s->fifo_fd);
65878a
-                if (r < 0)
65878a
-                        return r;
65878a
-
65878a
-                if (r == 0)
65878a
+                if (pipe_eof(s->fifo_fd) <= 0)
65878a
                         return 1;
65878a
         }
65878a
 
65878a
@@ -945,15 +1017,15 @@ void session_add_to_gc_queue(Session *s) {
65878a
 SessionState session_get_state(Session *s) {
65878a
         assert(s);
65878a
 
65878a
+        if (s->stopping || s->timer_fd >= 0)
65878a
+                return SESSION_CLOSING;
65878a
+
65878a
         if (s->closing)
65878a
                 return SESSION_CLOSING;
65878a
 
65878a
         if (s->scope_job)
65878a
                 return SESSION_OPENING;
65878a
 
65878a
-        if (s->fifo_fd < 0)
65878a
-                return SESSION_CLOSING;
65878a
-
65878a
         if (session_is_active(s))
65878a
                 return SESSION_ACTIVE;
65878a
 
65878a
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
65878a
index f175a89..9b76582 100644
65878a
--- a/src/login/logind-session.h
65878a
+++ b/src/login/logind-session.h
65878a
@@ -98,11 +98,14 @@ struct Session {
65878a
         int fifo_fd;
65878a
         char *fifo_path;
65878a
 
65878a
+        int timer_fd;
65878a
+
65878a
         bool idle_hint;
65878a
         dual_timestamp idle_hint_timestamp;
65878a
 
65878a
         bool in_gc_queue:1;
65878a
         bool started:1;
65878a
+        bool stopping:1;
65878a
         bool closing:1;
65878a
 
65878a
         DBusMessage *create_message;
65878a
@@ -130,6 +133,7 @@ void session_remove_fifo(Session *s);
65878a
 int session_start(Session *s);
65878a
 int session_stop(Session *s);
65878a
 int session_finalize(Session *s);
65878a
+void session_release(Session *s);
65878a
 int session_save(Session *s);
65878a
 int session_load(Session *s);
65878a
 int session_kill(Session *s, KillWho who, int signo);
65878a
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
65878a
index 8e7256b..653574e 100644
65878a
--- a/src/login/logind-user.c
65878a
+++ b/src/login/logind-user.c
65878a
@@ -487,6 +487,8 @@ int user_stop(User *u) {
65878a
         if (k < 0)
65878a
                 r = k;
65878a
 
65878a
+        u->stopping = true;
65878a
+
65878a
         user_save(u);
65878a
 
65878a
         return r;
65878a
@@ -602,22 +604,27 @@ void user_add_to_gc_queue(User *u) {
65878a
 
65878a
 UserState user_get_state(User *u) {
65878a
         Session *i;
65878a
-        bool all_closing = true;
65878a
 
65878a
         assert(u);
65878a
 
65878a
+        if (u->stopping)
65878a
+                return USER_CLOSING;
65878a
+
65878a
         if (u->slice_job || u->service_job)
65878a
                 return USER_OPENING;
65878a
 
65878a
-        LIST_FOREACH(sessions_by_user, i, u->sessions) {
65878a
-                if (session_is_active(i))
65878a
-                        return USER_ACTIVE;
65878a
-                if (session_get_state(i) != SESSION_CLOSING)
65878a
-                        all_closing = false;
65878a
-        }
65878a
+        if (u->sessions) {
65878a
+                bool all_closing = true;
65878a
+
65878a
+                LIST_FOREACH(sessions_by_user, i, u->sessions) {
65878a
+                        if (session_is_active(i))
65878a
+                                return USER_ACTIVE;
65878a
+                        if (session_get_state(i) != SESSION_CLOSING)
65878a
+                                all_closing = false;
65878a
+                }
65878a
 
65878a
-        if (u->sessions)
65878a
                 return all_closing ? USER_CLOSING : USER_ONLINE;
65878a
+        }
65878a
 
65878a
         if (user_check_linger_file(u) > 0)
65878a
                 return USER_LINGERING;
65878a
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
65878a
index a36f456..a12532e 100644
65878a
--- a/src/login/logind-user.h
65878a
+++ b/src/login/logind-user.h
65878a
@@ -61,6 +61,7 @@ struct User {
65878a
 
65878a
         bool in_gc_queue:1;
65878a
         bool started:1;
65878a
+        bool stopping:1;
65878a
 
65878a
         LIST_HEAD(Session, sessions);
65878a
         LIST_FIELDS(User, gc_queue);
65878a
diff --git a/src/login/logind.c b/src/login/logind.c
65878a
index 0628032..5180be7 100644
65878a
--- a/src/login/logind.c
65878a
+++ b/src/login/logind.c
65878a
@@ -80,10 +80,11 @@ Manager *manager_new(void) {
65878a
         m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
65878a
         m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
65878a
         m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
65878a
+        m->timer_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
65878a
 
65878a
         if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames ||
65878a
             !m->user_units || !m->session_units ||
65878a
-            !m->session_fds || !m->inhibitor_fds || !m->button_fds) {
65878a
+            !m->session_fds || !m->inhibitor_fds || !m->button_fds || !m->timer_fds) {
65878a
                 manager_free(m);
65878a
                 return NULL;
65878a
         }
65878a
@@ -149,6 +150,7 @@ void manager_free(Manager *m) {
65878a
         hashmap_free(m->session_fds);
65878a
         hashmap_free(m->inhibitor_fds);
65878a
         hashmap_free(m->button_fds);
65878a
+        hashmap_free(m->timer_fds);
65878a
 
65878a
         if (m->console_active_fd >= 0)
65878a
                 close_nointr_nofail(m->console_active_fd);
65878a
@@ -620,6 +622,13 @@ static void manager_dispatch_other(Manager *m, int fd) {
65878a
                 return;
65878a
         }
65878a
 
65878a
+        s = hashmap_get(m->timer_fds, INT_TO_PTR(fd + 1));
65878a
+        if (s) {
65878a
+                assert(s->timer_fd == fd);
65878a
+                session_stop(s);
65878a
+                return;
65878a
+        }
65878a
+
65878a
         i = hashmap_get(m->inhibitor_fds, INT_TO_PTR(fd + 1));
65878a
         if (i) {
65878a
                 assert(i->fifo_fd == fd);
65878a
@@ -942,8 +951,12 @@ void manager_gc(Manager *m, bool drop_not_started) {
65878a
                 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
65878a
                 session->in_gc_queue = false;
65878a
 
65878a
-                if (session_check_gc(session, drop_not_started) == 0) {
65878a
+                /* First, if we are not closing yet, initiate stopping */
65878a
+                if (!session_check_gc(session, drop_not_started) &&
65878a
+                    session_get_state(session) != SESSION_CLOSING)
65878a
                         session_stop(session);
65878a
+
65878a
+                if (!session_check_gc(session, drop_not_started)) {
65878a
                         session_finalize(session);
65878a
                         session_free(session);
65878a
                 }
65878a
@@ -953,8 +966,11 @@ void manager_gc(Manager *m, bool drop_not_started) {
65878a
                 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
65878a
                 user->in_gc_queue = false;
65878a
 
65878a
-                if (user_check_gc(user, drop_not_started) == 0) {
65878a
+                if (!user_check_gc(user, drop_not_started) &&
65878a
+                    user_get_state(user) != USER_CLOSING)
65878a
                         user_stop(user);
65878a
+
65878a
+                if (!user_check_gc(user, drop_not_started)) {
65878a
                         user_finalize(user);
65878a
                         user_free(user);
65878a
                 }
65878a
@@ -1032,6 +1048,7 @@ finish:
65878a
 
65878a
         return r;
65878a
 }
65878a
+
65878a
 int manager_startup(Manager *m) {
65878a
         int r;
65878a
         Seat *seat;
65878a
diff --git a/src/login/logind.h b/src/login/logind.h
65878a
index 9e6296c..0d2248f 100644
65878a
--- a/src/login/logind.h
65878a
+++ b/src/login/logind.h
65878a
@@ -88,6 +88,7 @@ struct Manager {
65878a
         Hashmap *session_fds;
65878a
         Hashmap *inhibitor_fds;
65878a
         Hashmap *button_fds;
65878a
+        Hashmap *timer_fds;
65878a
 
65878a
         usec_t inhibit_delay_max;
65878a
 
65878a
@@ -183,9 +184,10 @@ int manager_send_changed(Manager *manager, const char *properties);
65878a
 
65878a
 int manager_dispatch_delayed(Manager *manager);
65878a
 
65878a
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *kill_mode, DBusError *error, char **job);
65878a
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, DBusError *error, char **job);
65878a
 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job);
65878a
 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
65878a
+int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error);
65878a
 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
65878a
 int manager_unit_is_active(Manager *manager, const char *unit);
65878a
 
65878a
diff --git a/src/login/pam-module.c b/src/login/pam-module.c
65878a
index 22d9733..7bd4783 100644
65878a
--- a/src/login/pam-module.c
65878a
+++ b/src/login/pam-module.c
65878a
@@ -478,7 +478,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
65878a
                 int flags,
65878a
                 int argc, const char **argv) {
65878a
 
65878a
-        const void *p = NULL, *existing = NULL;
65878a
+        const void *existing = NULL;
65878a
         const char *id;
65878a
         DBusConnection *bus = NULL;
65878a
         DBusMessage *m = NULL, *reply = NULL;
65878a
@@ -535,12 +535,15 @@ _public_ PAM_EXTERN int pam_sm_close_session(
65878a
                 }
65878a
         }
65878a
 
65878a
+
65878a
+        /* Note that we are knowingly leaking the FIFO fd here. This
65878a
+         * way, logind can watch us die. If we closed it here it would
65878a
+         * not have any clue when that is completed. Given that one
65878a
+         * cannot really have multiple PAM sessions open from the same
65878a
+         * process this means we will leak one FD at max. */
65878a
         r = PAM_SUCCESS;
65878a
 
65878a
 finish:
65878a
-        pam_get_data(handle, "systemd.session-fd", &p);
65878a
-        if (p)
65878a
-                close_nointr(PTR_TO_INT(p) - 1);
65878a
 
65878a
         dbus_error_free(&error);
65878a