logind-session.c revision bf7825ae69f53a7e80a740547919833e49ed1df4
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering This file is part of systemd.
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering Copyright 2011 Lennart Poettering
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering systemd is free software; you can redistribute it and/or modify it
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering under the terms of the GNU Lesser General Public License as published by
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering (at your option) any later version.
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering systemd is distributed in the hope that it will be useful, but
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering Lesser General Public License for more details.
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering You should have received a copy of the GNU Lesser General Public License
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen#include <systemd/sd-messages.h>
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart PoetteringSession* session_new(Manager *m, const char *id) {
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering s->state_file = strappend("/run/systemd/sessions/", id);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering s->id = path_get_file_name(s->state_file);
b1d5277372a26e5a5b9980174652e1e287ba6b14Lennart Poettering if (hashmap_put(m->sessions, s->id, s) < 0) {
b1d5277372a26e5a5b9980174652e1e287ba6b14Lennart Poettering LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering hashmap_remove(s->manager->session_units, s->scope);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering hashmap_remove(s->manager->sessions, s->id);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poetteringvoid session_set_user(Session *s, User *u) {
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering r = fopen_temporary(s->state_file, &f, &temp_path);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering "# This is private data. Do not parse.\n"
67c7c892b9fcb946792b380a30c4ba704c700934Lennart Poettering "REMOTE=%i\n",
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering session_state_to_string(session_get_state(s)),
67c7c892b9fcb946792b380a30c4ba704c700934Lennart Poettering fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (dual_timestamp_is_set(&s->timestamp))
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering "REALTIME=%llu\n"
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering "MONOTONIC=%llu\n",
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering (unsigned long long) s->timestamp.realtime,
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering (unsigned long long) s->timestamp.monotonic);
67c7c892b9fcb946792b380a30c4ba704c700934Lennart Poettering if (ferror(f) || rename(temp_path, s->state_file) < 0) {
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering r = parse_env_file(s->state_file, NEWLINE,
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering log_error("Failed to read %s: %s", s->state_file, strerror(-r));
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering log_error("UID not specified for session %s", s->id);
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering log_error("Failed to parse UID value %s for session %s.", uid, s->id);
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
d02608170e599b1ffbc7c9a22062bae2579d6e36Lennart Poettering log_error("User of session %s not known.", s->id);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering o = hashmap_get(s->manager->seats, seat);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (vtnr && s->seat && seat_has_vts(s->seat)) {
67c7c892b9fcb946792b380a30c4ba704c700934Lennart Poettering if (k >= 0 && v >= 1)
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering audit_session_from_pid(s->leader, &s->audit_id);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering /* If we open an unopened pipe for reading we will not
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering get an EOF. to trigger an EOF we hence open it for
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering reading, but close it right-away which then will
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering trigger the EOF. */
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering unsigned long long l;
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering unsigned long long l;
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poetteringstatic int session_link_x11_socket(Session *s) {
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering _cleanup_free_ char *t = NULL, *f = NULL;
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (!s->display || !display_is_local(s->display))
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering f = new(char, sizeof("/tmp/.X11-unix/X") + k);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering /* Note that this cannot be in a subdir to avoid
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering * vulnerabilities since we are privileged but the runtime
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering * path is owned by the user */
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering t = strappend(s->user->runtime_path, "/X11-display");
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (link(f, t) < 0) {
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (link(f, t) >= 0)
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (symlink(f, t) < 0) {
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering if (symlink(f, t) >= 0)
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering log_error("Failed to link %s to %s: %m", f, t);
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poetteringstatic int session_start_scope(Session *s) {
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poettering description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poettering scope = strjoin("session-", s->id, ".scope", NULL);
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poettering kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poettering r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poettering log_error("Failed to start session scope %s: %s %s",
e929bee09ab8000e87b7e825ed3a78d73ecdd7f0Lennart Poettering scope, bus_error(&error, r), error.name);
if (s->scope)
assert(s);
if (!s->user)
return -ESTALE;
if (s->started)
r = session_start_scope(s);
NULL);
if (s->seat)
s->started = true;
session_save(s);
session_send_signal(s, true);
if (s->seat) {
char *job;
assert(s);
if (!s->scope)
assert(s);
return log_oom();
r = unlink(t);
return r < 0 ? -errno : 0;
assert(s);
if (!s->user)
return -ESTALE;
r = session_stop_scope(s);
session_save(s);
assert(s);
if (!s->user)
return -ESTALE;
if (s->started)
NULL);
if (s->started) {
session_send_signal(s, false);
s->started = false;
if (s->seat) {
assert(s);
if (!s->seat)
return -ENOMEM;
tty = p;
return -ENOENT;
return -errno;
assert(s);
if (s->idle_hint) {
*t = s->idle_hint_timestamp;
return s->idle_hint;
if (s->display)
goto dont_know;
if (s->tty) {
goto found_atime;
if (s->leader > 0) {
goto found_atime;
*t = s->idle_hint_timestamp;
assert(s);
if (s->idle_hint == b)
s->idle_hint = b;
if (s->seat)
assert(s);
if (!s->fifo_path) {
return -ENOMEM;
return -errno;
if (s->fifo_fd < 0) {
if (s->fifo_fd < 0)
return -errno;
return -errno;
return -errno;
assert(s);
if (s->fifo_fd >= 0) {
session_save(s);
if (s->fifo_path) {
assert(s);
if (!s->user)
if (s->fifo_fd >= 0) {
if (s->scope_job)
if (s->scope)
assert(s);
if (s->in_gc_queue)
s->in_gc_queue = true;
assert(s);
if (s->closing)
return SESSION_CLOSING;
if (s->scope_job)
return SESSION_OPENING;
if (s->fifo_fd < 0)
return SESSION_CLOSING;
if (session_is_active(s))
return SESSION_ACTIVE;
return SESSION_ONLINE;
assert(s);
if (!s->scope)
return -ESRCH;
assert(s);
assert(s);
return -EBUSY;
return -ENOMEM;
free(t);
s->controller = t;
assert(s);
if (!s->controller)