logind: implement D-Bus properties

This commit is contained in:
Lennart Poettering 2011-05-26 02:21:16 +02:00
parent bd253d1b91
commit 3f49d45a45
15 changed files with 1141 additions and 36 deletions

View file

@ -810,10 +810,14 @@ systemd_hostnamed_LDADD = \
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 \

72
src/70-uaccess.rules Normal file
View file

@ -0,0 +1,72 @@
# 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"

20
src/71-seat.rules Normal file
View file

@ -0,0 +1,20 @@
# 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"

235
src/logind-dbus.c Normal file
View file

@ -0,0 +1,235 @@
/*-*- 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
};

View file

@ -80,6 +80,6 @@ void device_attach(Device *d, Seat *s) {
if (d->seat)
device_detach(d);
LIST_PREPEND(Device, devices, d->seat->devices, d);
d->seat = s;
LIST_PREPEND(Device, devices, s->devices, d);
}

218
src/logind-seat-dbus.c Normal file
View file

@ -0,0 +1,218 @@
/*-*- 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;
}

View file

@ -182,7 +182,8 @@ static int vt_allocate(int vtnr) {
}
static int seat_preallocate_vts(Seat *s) {
int i, r = 0;
int r = 0;
unsigned i;
assert(s);
assert(s->manager);
@ -295,6 +296,11 @@ int seat_read_active_vt(Seat *s) {
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);
@ -304,6 +310,8 @@ int seat_start(Seat *s) {
/* Save seat data */
seat_save(s);
s->started = true;
return 0;
}
@ -313,6 +321,11 @@ int seat_stop(Seat *s) {
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)
@ -322,6 +335,8 @@ int seat_stop(Seat *s) {
unlink(s->state_file);
seat_add_to_gc_queue(s);
s->started = false;
return r;
}
@ -343,3 +358,30 @@ void seat_add_to_gc_queue(Seat *s) {
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;
}

View file

@ -42,6 +42,7 @@ struct Seat {
LIST_HEAD(Session, sessions);
bool in_gc_queue:1;
bool started:1;
LIST_FIELDS(Seat, gc_queue);
};
@ -62,4 +63,9 @@ int seat_stop(Seat *s);
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

256
src/logind-session-dbus.c Normal file
View file

@ -0,0 +1,256 @@
/*-*- 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;
}

View file

@ -83,6 +83,7 @@ void session_free(Session *s) {
free(s->tty);
free(s->display);
free(s->remote_host);
free(s->remote_user);
hashmap_remove(s->manager->sessions, s->id);
@ -147,6 +148,11 @@ int session_save(Session *s) {
"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",
@ -495,7 +501,7 @@ void session_add_to_gc_queue(Session *s) {
}
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
[SESSION_TERMINAL] = "terminal",
[SESSION_TTY] = "tty",
[SESSION_X11] = "x11"
};

View file

@ -31,7 +31,7 @@ typedef struct Session Session;
#include "logind-user.h"
typedef enum SessionType {
SESSION_TERMINAL,
SESSION_TTY,
SESSION_X11,
_SESSION_TYPE_MAX,
_SESSION_TYPE_INVALID = -1
@ -53,20 +53,21 @@ struct Session {
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);
@ -86,6 +87,10 @@ int session_stop(Session *s);
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);

240
src/logind-user-dbus.c Normal file
View file

@ -0,0 +1,240 @@
/*-*- 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;
}

View file

@ -70,6 +70,10 @@ UserState user_get_state(User *u);
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);

View file

@ -255,9 +255,15 @@ int manager_process_device(Manager *m, struct udev_device *d) {
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;
@ -268,14 +274,16 @@ int manager_process_device(Manager *m, struct udev_device *d) {
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;
@ -288,6 +296,7 @@ int manager_process_device(Manager *m, struct udev_device *d) {
}
device_attach(device, seat);
seat_start(seat);
}
return 0;
@ -373,9 +382,6 @@ int manager_enumerate_seats(Manager *m) {
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);
@ -676,27 +682,15 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
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;
@ -714,13 +708,11 @@ static int manager_connect_bus(Manager *m) {
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;
@ -931,6 +923,9 @@ int manager_run(Manager *m) {
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;
}

View file

@ -72,14 +72,14 @@ struct Manager {
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;
};
@ -111,4 +111,6 @@ void manager_gc(Manager *m);
bool x11_display_is_local(const char *display);
extern const DBusObjectPathVTable bus_manager_vtable;
#endif