systemd_logind_SOURCES = \
src/logind.c \
+ src/logind-dbus.c \
src/logind-device.c \
src/logind-seat.c \
+ src/logind-seat-dbus.c \
src/logind-session.c \
+ src/logind-session-dbus.c \
src/logind-user.c \
+ src/logind-user-dbus.c \
src/logind-acl.c \
src/dbus-common.c \
src/dbus-loop.c \
--- /dev/null
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+ACTION=="remove", GOTO="uaccess_end"
+ENV{MAJOR}=="", GOTO="uaccess_end"
+
+# PTP/MTP protocol devices, cameras, portable media players
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p"
+SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess"
+
+# Digicams with proprietary protocol
+ENV{ID_GPHOTO2}=="*?", TAG+="uaccess"
+
+# SCSI and USB scanners
+ENV{libsane_matched}=="yes", TAG+="uaccess"
+
+# HPLIP devices (necessary for ink level check and HP tool maintenance)
+ENV{ID_HPLIP}=="1", TAG+="uaccess"
+
+# optical drives
+SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess"
+SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess"
+
+# Sound devices
+SUBSYSTEM=="sound", TAG+="uaccess"
+
+# ffado is an userspace driver for firewire sound cards
+SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess"
+
+# Webcams, frame grabber, TV cards
+SUBSYSTEM=="video4linux", TAG+="uaccess"
+SUBSYSTEM=="dvb", TAG+="uaccess"
+
+# IIDC devices: industrial cameras and some webcams
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess"
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess"
+# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess"
+SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess"
+
+# DRI video devices
+SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess"
+
+# KVM
+SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"
+
+# smart-card readers
+ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess"
+
+# PDA devices
+ENV{ID_PDA}=="*?", TAG+="uaccess"
+
+# Programmable remote control
+ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess"
+
+# joysticks
+SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess"
+
+# color measurement devices
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess"
+
+# DDC/CI device, usually high-end monitors such as the DreamColor
+ENV{DDC_DEVICE}=="*?", TAG+="uaccess"
+
+# media player raw devices (for user-mode drivers, Android SDK, etc.)
+SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess"
+
+LABEL="uaccess_end"
--- /dev/null
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+ACTION=="remove", GOTO="seat_end"
+
+TAG=="uaccess", TAG+="seat"
+SUBSYSTEM=="input", TAG+="seat"
+SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat"
+SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
+SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="0001", ENV{ID_AUTOSEAT}="1"
+
+IMPORT{parent}="ID_SEAT"
+ENV{ID_AUTOSEAT}=="1", ENV{ID_SEAT}=="", ENV{ID_SEAT}="seat-foo"
+ENV{ID_SEAT}!="", TAG+="seat-foo"
+
+LABEL="seat_end"
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "logind.h"
+#include "dbus-common.h"
+
+#define BUS_MANAGER_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.Manager\">\n" \
+ " <method name=\"GetSeat\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetUser\">\n" \
+ " <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n" \
+ " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetSession\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ListSeats\">\n" \
+ " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ListUsers\">\n" \
+ " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ListSessions\">\n" \
+ " <arg name=\"users\" type=\"a(sussso)\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"CreateSession\">\n" \
+ " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
+ " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
+ " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
+ " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"kill_processes\" type=\"as\" direction=\"in\"/>\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
+ " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
+ " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"TerminateSession\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"TerminateUser\">\n" \
+ " <arg name=\"uid\" type=\"t\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <method name=\"TerminateSeat\">\n" \
+ " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
+ " </method>\n" \
+ " <signal name=\"SessionNew\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"SessionRemoved\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"UserNew\">\n" \
+ " <arg name=\"uid\" type=\"u\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"UserRemoved\">\n" \
+ " <arg name=\"uid\" type=\"u\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"SeatNew\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"SeatRemoved\">\n" \
+ " <arg name=\"id\" type=\"s\"/>\n" \
+ " <arg name=\"path\" type=\"o\"/>\n" \
+ " </signal>\n" \
+ " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION_BEGIN \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_MANAGER_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE
+
+#define INTROSPECTION_END \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.Manager\0"
+
+static DBusHandlerResult manager_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
+ { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
+ { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
+ { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
+ { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
+ { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
+ { "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ DBusError error;
+ DBusMessage *reply = NULL;
+
+ assert(connection);
+ assert(message);
+ assert(m);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ char *introspection = NULL;
+ FILE *f;
+ Iterator i;
+ Session *session;
+ Seat *seat;
+ User *user;
+ size_t size;
+ char *p;
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ /* We roll our own introspection code here, instead of
+ * relying on bus_default_message_handler() because we
+ * need to generate our introspection string
+ * dynamically. */
+
+ if (!(f = open_memstream(&introspection, &size)))
+ goto oom;
+
+ fputs(INTROSPECTION_BEGIN, f);
+
+ HASHMAP_FOREACH(seat, m->seats, i) {
+ p = bus_path_escape(seat->id);
+
+ if (p) {
+ fprintf(f, "<node name=\"seat/%s\"/>", p);
+ free(p);
+ }
+ }
+
+ HASHMAP_FOREACH(user, m->users, i)
+ fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
+
+ HASHMAP_FOREACH(session, m->sessions, i) {
+ p = bus_path_escape(session->id);
+
+ if (p) {
+ fprintf(f, "<node name=\"session/%s\"/>", p);
+ free(p);
+ }
+ }
+
+ fputs(INTROSPECTION_END, f);
+
+ if (ferror(f)) {
+ fclose(f);
+ free(introspection);
+ goto oom;
+ }
+
+ fclose(f);
+
+ if (!introspection)
+ goto oom;
+
+ if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
+ free(introspection);
+ goto oom;
+ }
+
+ free(introspection);
+ } else
+ return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties);
+
+ if (reply) {
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+const DBusObjectPathVTable bus_manager_vtable = {
+ .message_function = manager_message_handler
+};
if (d->seat)
device_detach(d);
- LIST_PREPEND(Device, devices, d->seat->devices, d);
d->seat = s;
+ LIST_PREPEND(Device, devices, s->devices, d);
}
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-seat.h"
+#include "dbus-common.h"
+#include "util.h"
+
+#define BUS_SEAT_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.Seat\">\n" \
+ " <method name=\"Terminate\"/>\n" \
+ " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Active\" type=\"so\" access=\"read\"/>\n" \
+ " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+ " </interface>\n" \
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_SEAT_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.Seat\0"
+
+static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ Seat *s = data;
+ const char *id, *path;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ if (s->active) {
+ id = s->active->id;
+ path = p = session_bus_path(s->active);
+
+ if (!p)
+ return -ENOMEM;
+ } else {
+ id = "";
+ path = "/";
+ }
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ Seat *s = data;
+ Session *session;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(sessions_by_seat, session, s->sessions) {
+ char *p;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ return -ENOMEM;
+
+ p = session_bus_path(session);
+ if (!p)
+ return -ENOMEM;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
+ Seat *s;
+ char *id;
+
+ assert(m);
+ assert(path);
+ assert(_s);
+
+ if (!startswith(path, "/org/freedesktop/login1/seat/"))
+ return -EINVAL;
+
+ id = bus_path_unescape(path + 29);
+ if (!id)
+ return -ENOMEM;
+
+ s = hashmap_get(m->seats, id);
+ free(id);
+
+ if (!s)
+ return -ENOENT;
+
+ *_s = s;
+ return 0;
+}
+
+static DBusHandlerResult seat_message_dispatch(
+ Seat *s,
+ DBusConnection *connection,
+ DBusMessage *message) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.Seat", "Id", bus_property_append_string, "s", s->id },
+ { "org.freedesktop.login1.Seat", "Active", bus_seat_append_active, "(so)", s },
+ { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ assert(s);
+ assert(connection);
+ assert(message);
+
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult seat_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ Seat *s;
+ int r;
+
+ r = get_seat_for_path(m, dbus_message_get_path(message), &s);
+ if (r < 0) {
+
+ if (r == -ENOMEM)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (r == -ENOENT) {
+ DBusError e;
+
+ dbus_error_init(&e);
+ dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
+ return bus_send_error_reply(connection, message, &e, r);
+ }
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ return seat_message_dispatch(s, connection, message);
+}
+
+const DBusObjectPathVTable bus_seat_vtable = {
+ .message_function = seat_message_handler
+};
+
+char *seat_bus_path(Seat *s) {
+ char *t, *r;
+
+ assert(s);
+
+ t = bus_path_escape(s->id);
+ if (!t)
+ return NULL;
+
+ r = strappend("/org/freedesktop/login1/seat/", t);
+ free(t);
+
+ return r;
+}
}
static int seat_preallocate_vts(Seat *s) {
- int i, r = 0;
+ int r = 0;
+ unsigned i;
assert(s);
assert(s->manager);
int seat_start(Seat *s) {
assert(s);
+ if (s->started)
+ return 0;
+
+ log_info("New seat %s.", s->id);
+
/* Initialize VT magic stuff */
seat_preallocate_vts(s);
/* Save seat data */
seat_save(s);
+ s->started = true;
+
return 0;
}
assert(s);
+ if (!s->started)
+ return 0;
+
+ log_info("Removed seat %s.", s->id);
+
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
k = session_stop(session);
if (k < 0)
unlink(s->state_file);
seat_add_to_gc_queue(s);
+ s->started = false;
+
return r;
}
LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s);
s->in_gc_queue = true;
}
+
+static bool seat_name_valid_char(char c) {
+ return
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '-' ||
+ c == '_';
+}
+
+bool seat_name_is_valid(const char *name) {
+ const char *p;
+
+ assert(name);
+
+ if (!startswith(name, "seat"))
+ return false;
+
+ if (!name[4])
+ return false;
+
+ for (p = name; *p; p++)
+ if (!seat_name_valid_char(*p))
+ return false;
+
+ return true;
+}
LIST_HEAD(Session, sessions);
bool in_gc_queue:1;
+ bool started:1;
LIST_FIELDS(Seat, gc_queue);
};
int seat_check_gc(Seat *s);
void seat_add_to_gc_queue(Seat *s);
+bool seat_name_is_valid(const char *name);
+char *seat_bus_path(Seat *s);
+
+extern const DBusObjectPathVTable bus_seat_vtable;
+
#endif
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-session.h"
+#include "dbus-common.h"
+#include "util.h"
+
+#define BUS_SESSION_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.Session\">\n" \
+ " <method name=\"Terminate\"/>\n" \
+ " <method name=\"Activate\"/>\n" \
+ " <property name=\"Id\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
+ " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
+ " <property name=\"TTY\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Display\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
+ " </interface>\n"
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_SESSION_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.Session\0"
+
+static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ Session *s = data;
+ const char *id, *path;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ if (s->seat) {
+ id = s->seat->id;
+ path = p = seat_bus_path(s->seat);
+
+ if (!p)
+ return -ENOMEM;
+ } else {
+ id = "";
+ path = "/";
+ }
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ Session *s = data;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ p = user_bus_path(s->user);
+ if (!p)
+ return -ENOMEM;
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &s->user->uid) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
+ Session *s = data;
+ bool b;
+
+ assert(i);
+ assert(property);
+ assert(s);
+
+ b = session_is_active(s);
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
+
+static int get_session_for_path(Manager *m, const char *path, Session **_s) {
+ Session *s;
+ char *id;
+
+ assert(m);
+ assert(path);
+ assert(_s);
+
+ if (!startswith(path, "/org/freedesktop/login1/session/"))
+ return -EINVAL;
+
+ id = bus_path_unescape(path + 32);
+ if (!id)
+ return -ENOMEM;
+
+ s = hashmap_get(m->sessions, id);
+ free(id);
+
+ if (!s)
+ return -ENOENT;
+
+ *_s = s;
+ return 0;
+}
+
+static DBusHandlerResult session_message_dispatch(
+ Session *s,
+ DBusConnection *connection,
+ DBusMessage *message) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id },
+ { "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s },
+ { "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name },
+ { "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path },
+ { "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr },
+ { "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s },
+ { "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty },
+ { "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display },
+ { "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
+ { "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
+ { "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
+ { "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
+ { "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
+ { "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
+ { "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s },
+ { "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers },
+ { "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers },
+ { "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ assert(s);
+ assert(connection);
+ assert(message);
+
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult session_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ Session *s;
+ int r;
+
+ r = get_session_for_path(m, dbus_message_get_path(message), &s);
+ if (r < 0) {
+
+ if (r == -ENOMEM)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (r == -ENOENT) {
+ DBusError e;
+
+ dbus_error_init(&e);
+ dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
+ return bus_send_error_reply(connection, message, &e, r);
+ }
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ return session_message_dispatch(s, connection, message);
+}
+
+const DBusObjectPathVTable bus_session_vtable = {
+ .message_function = session_message_handler
+};
+
+char *session_bus_path(Session *s) {
+ char *t, *r;
+
+ assert(s);
+
+ t = bus_path_escape(s->id);
+ if (!t)
+ return NULL;
+
+ r = strappend("/org/freedesktop/login1/session/", t);
+ free(t);
+
+ return r;
+}
free(s->tty);
free(s->display);
free(s->remote_host);
+ free(s->remote_user);
hashmap_remove(s->manager->sessions, s->id);
"REMOTE_HOST=%s\n",
s->remote_host);
+ if (s->remote_user)
+ fprintf(f,
+ "REMOTE_USER=%s\n",
+ s->remote_user);
+
if (s->seat && s->seat->manager->vtconsole == s->seat)
fprintf(f,
"VTNR=%i\n",
}
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
- [SESSION_TERMINAL] = "terminal",
+ [SESSION_TTY] = "tty",
[SESSION_X11] = "x11"
};
#include "logind-user.h"
typedef enum SessionType {
- SESSION_TERMINAL,
+ SESSION_TTY,
SESSION_X11,
_SESSION_TYPE_MAX,
_SESSION_TYPE_INVALID = -1
char *display;
bool remote;
+ char *remote_user;
char *remote_host;
int vtnr;
Seat *seat;
pid_t leader;
- uint64_t audit_id;
+ uint32_t audit_id;
int pipe_fd;
char *cgroup_path;
char **controllers, **reset_controllers;
- bool kill_processes:1;
+ bool kill_processes;
bool in_gc_queue:1;
LIST_FIELDS(Session, sessions_by_user);
int session_save(Session *s);
int session_load(Session *s);
+char *session_bus_path(Session *s);
+
+extern const DBusObjectPathVTable bus_session_vtable;
+
const char* session_type_to_string(SessionType t);
SessionType session_type_from_string(const char *s);
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "logind.h"
+#include "logind-user.h"
+#include "dbus-common.h"
+
+#define BUS_USER_INTERFACE \
+ " <interface name=\"org.freedesktop.login1.User\">\n" \
+ " <method name=\"Terminate\"/>\n" \
+ " <property name=\"UID\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"GID\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
+ " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
+ " </interface>\n" \
+
+#define INTROSPECTION \
+ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
+ "<node>\n" \
+ BUS_USER_INTERFACE \
+ BUS_PROPERTIES_INTERFACE \
+ BUS_PEER_INTERFACE \
+ BUS_INTROSPECTABLE_INTERFACE \
+ "</node>\n"
+
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.login1.User\0"
+
+static int bus_user_append_display(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub;
+ User *u = data;
+ const char *id, *path;
+ char *p = NULL;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
+ return -ENOMEM;
+
+ if (u->display) {
+ id = u->display->id;
+ path = p = session_bus_path(u->display);
+
+ if (!p)
+ return -ENOMEM;
+ } else {
+ id = "";
+ path = "/";
+ }
+
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_user_append_state(DBusMessageIter *i, const char *property, void *data) {
+ User *u = data;
+ const char *state;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ state = user_state_to_string(user_get_state(u));
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int bus_user_append_sessions(DBusMessageIter *i, const char *property, void *data) {
+ DBusMessageIter sub, sub2;
+ User *u = data;
+ Session *session;
+
+ assert(i);
+ assert(property);
+ assert(u);
+
+ if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "so", &sub))
+ return -ENOMEM;
+
+ LIST_FOREACH(sessions_by_user, session, u->sessions) {
+ char *p;
+
+ if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
+ return -ENOMEM;
+
+ p = session_bus_path(session);
+ if (!p)
+ return -ENOMEM;
+
+ if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
+ free(p);
+ return -ENOMEM;
+ }
+
+ free(p);
+
+ if (!dbus_message_iter_close_container(&sub, &sub2))
+ return -ENOMEM;
+ }
+
+ if (!dbus_message_iter_close_container(i, &sub))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int get_user_for_path(Manager *m, const char *path, User **_u) {
+ User *u;
+ unsigned long lu;
+ int r;
+
+ assert(m);
+ assert(path);
+ assert(_u);
+
+ if (!startswith(path, "/org/freedesktop/login1/user/"))
+ return -EINVAL;
+
+ r = safe_atolu(path + 29, &lu);
+ if (r < 0)
+ return r;
+
+ u = hashmap_get(m->users, ULONG_TO_PTR(lu));
+ if (!u)
+ return -ENOENT;
+
+ *_u = u;
+ return 0;
+}
+
+static DBusHandlerResult user_message_dispatch(
+ User *u,
+ DBusConnection *connection,
+ DBusMessage *message) {
+
+ const BusProperty properties[] = {
+ { "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid },
+ { "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid },
+ { "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name },
+ { "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path },
+ { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path },
+ { "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service },
+ { "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u },
+ { "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u },
+ { "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u },
+ { NULL, NULL, NULL, NULL, NULL }
+ };
+
+ assert(u);
+ assert(connection);
+ assert(message);
+
+ return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
+}
+
+static DBusHandlerResult user_message_handler(
+ DBusConnection *connection,
+ DBusMessage *message,
+ void *userdata) {
+
+ Manager *m = userdata;
+ User *u;
+ int r;
+
+ r = get_user_for_path(m, dbus_message_get_path(message), &u);
+ if (r < 0) {
+
+ if (r == -ENOMEM)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (r == -ENOENT) {
+ DBusError e;
+
+ dbus_error_init(&e);
+ dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown user");
+ return bus_send_error_reply(connection, message, &e, r);
+ }
+
+ return bus_send_error_reply(connection, message, NULL, r);
+ }
+
+ return user_message_dispatch(u, connection, message);
+}
+
+const DBusObjectPathVTable bus_user_vtable = {
+ .message_function = user_message_handler
+};
+
+char *user_bus_path(User *u) {
+ char *s;
+
+ assert(u);
+
+ if (asprintf(&s, "/org/freedesktop/login1/user/%llu", (unsigned long long) u->uid) < 0)
+ return NULL;
+
+ return s;
+}
int user_save(User *u);
int user_load(User *u);
+char *user_bus_path(User *s);
+
+extern const DBusObjectPathVTable bus_user_vtable;
+
const char* user_state_to_string(UserState s);
UserState user_state_from_string(const char *s);
assert(m);
+ /* FIXME: drop this check as soon as libudev's enum support
+ * honours tags and subsystem matches at the same time */
+ if (!streq_ptr(udev_device_get_subsystem(d), "graphics"))
+ return 0;
+
if (streq_ptr(udev_device_get_action(d), "remove")) {
- device = hashmap_get(m->devices, udev_device_get_syspath(d));
+ /* FIXME: use syspath instead of sysname here, as soon as fb driver is fixed */
+ device = hashmap_get(m->devices, udev_device_get_sysname(d));
if (!device)
return 0;
const char *sn;
Seat *seat;
- sn = udev_device_get_property_value(d, "SEAT");
+ sn = udev_device_get_property_value(d, "ID_SEAT");
if (!sn)
sn = "seat0";
- if (!startswith(sn, "seat"))
- return -EINVAL;
+ if (!seat_name_is_valid(sn)) {
+ log_warning("Device with invalid seat name %s found, ignoring.", sn);
+ return 0;
+ }
- r = manager_add_device(m, udev_device_get_syspath(d), &device);
+ r = manager_add_device(m, udev_device_get_sysname(d), &device);
if (r < 0)
return r;
}
device_attach(device, seat);
+ seat_start(seat);
}
return 0;
if (!dirent_is_file(de))
continue;
- if (!startswith(de->d_name, "seat"))
- continue;
-
s = hashmap_get(m->seats, de->d_name);
if (!s) {
unlinkat(dirfd(d), de->d_name, 0);
return 0;
}
-static DBusHandlerResult login_message_handler(
- DBusConnection *connection,
- DBusMessage *message,
- void *userdata) {
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
static DBusHandlerResult login_message_filter(
DBusConnection *connection,
DBusMessage *message,
void *userdata) {
- return DBUS_HANDLER_RESULT_HANDLED;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static int manager_connect_bus(Manager *m) {
- const DBusObjectPathVTable login_vtable = {
- .message_function = login_message_handler
- };
-
DBusError error;
int r;
struct epoll_event ev;
goto fail;
}
- if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &login_vtable, NULL)) {
- log_error("Not enough memory");
- r = -ENOMEM;
- goto fail;
- }
-
- if (!dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
+ if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
+ !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
+ !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
+ !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
+ !dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
log_error("Not enough memory");
r = -ENOMEM;
goto fail;
n = epoll_wait(m->epoll_fd, &event, 1, -1);
if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
log_error("epoll() failed: %m");
return -errno;
}
int bus_fd;
int epoll_fd;
- int n_autovts;
+ unsigned n_autovts;
Seat *vtconsole;
char *cgroup_path;
char **controllers, **reset_controllers;
- char **kill_only_users, **kill_exlude_users;
+ char **kill_only_users, **kill_exclude_users;
bool kill_user_processes;
};
bool x11_display_is_local(const char *display);
+extern const DBusObjectPathVTable bus_manager_vtable;
+
#endif