+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
+
+ /* We use the FIFO to detect stray sessions where the process
+ invoking PAM dies abnormally. We need to make sure that
+ that process is not killed if at the clean end of the
+ session it closes the FIFO. Hence, with this call
+ explicitly turn off the FIFO logic, so that the PAM code
+ can finish clean up on its own */
+ session_remove_fifo(session);
+ session_save(session);
+ user_save(session->user);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ Session *session;
+ const char *name;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
+
+ r = session_activate(session);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ const char *session_name, *seat_name;
+ Manager *m = userdata;
+ Session *session;
+ Seat *seat;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ /* Same as ActivateSession() but refuses to work if
+ * the seat doesn't match */
+
+ r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ session = hashmap_get(m->sessions, session_name);
+ if (!session)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", session_name);
+
+ seat = hashmap_get(m->seats, seat_name);
+ if (!seat)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", seat_name);
+
+ if (session->seat != seat)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
+
+ r = session_activate(session);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ Session *session;
+ const char *name;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
+
+ r = session_send_lock(session, streq(sd_bus_message_get_member(message), "LockSession"));
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ const char *name, *swho;
+ Manager *m = userdata;
+ Session *session;
+ int32_t signo;
+ KillWho who;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ if (isempty(swho))
+ who = KILL_ALL;
+ else {
+ who = kill_who_from_string(swho);
+ if (who < 0)
+ return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
+ }
+
+ if (signo <= 0 || signo >= _NSIG)
+ return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
+
+ r = session_kill(session, who, signo);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ uint32_t uid;
+ int32_t signo;
+ User *user;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "ui", &uid, &signo);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ if (signo <= 0 || signo >= _NSIG)
+ return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
+
+ user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+ if (!user)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
+
+ r = user_kill(user, signo);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ const char *name;
+ Session *session;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
+
+ r = session_stop(session);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ uint32_t uid;
+ User *user;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "u", &uid);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+ if (!user)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
+
+ r = user_stop(user);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ Manager *m = userdata;
+ const char *name;
+ Seat *seat;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ seat = hashmap_get(m->seats, name);
+ if (!seat)
+ return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
+
+ r = seat_stop_sessions(seat);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ return sd_bus_reply_method_return(bus, message, NULL);
+}
+
+static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *cc = NULL;
+ Manager *m = userdata;
+ int b, r;
+ struct passwd *pw;
+ const char *path;
+ uint32_t uid;
+ int interactive;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ errno = 0;
+ pw = getpwuid(uid);
+ if (!pw)
+ return sd_bus_reply_method_errno(bus, message, errno ? errno : ENOENT, NULL);
+
+ r = bus_verify_polkit_async(bus,
+ &m->polkit_registry,
+ message,
+ "org.freedesktop.login1.set-user-linger",
+ interactive,
+ &error,
+ method_set_user_linger, m);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, &error);
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ mkdir_p_label("/var/lib/systemd", 0755);
+
+ r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ cc = cescape(pw->pw_name);
+ if (!cc)
+ return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
+
+ path = strappenda("/var/lib/systemd/linger/", cc);
+ if (b) {
+ User *u;
+
+ r = touch(path);
+ if (r < 0)
+ return sd_bus_reply_method_errno(bus, message, r, NULL);
+
+ if (manager_add_user_by_uid(m, uid, &u) >= 0)
+ user_start(u);
+
+ } else {
+ User *u;
+
+ r = unlink(path);
+ if (r < 0 && errno != ENOENT)
+ return sd_bus_reply_method_errno(bus, message, errno, NULL);
+
+ u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
+ if (u)
+ user_add_to_gc_queue(u);
+ }
+
+ return sd_bus_reply_method_return(bus, message, NULL);