Skip to content

Commit

Permalink
logind: make "self" and "auto" magic strings when operating on seats …
Browse files Browse the repository at this point in the history
…+ sessions

Most of the operations one can do on sessions so far accepted an empty
session name as a shortcut for the caller's session. This is quite
useful traditionally, but much less useful than it used to be, since
most user code now (rightfully) runs in --user context, not in a
session.

With this change we tweak the logic a bit: we introduce the two special
session and seat names "self" and "auto". The former refers to the
session/seat the client is in, and is hence mostly equivalent to te
empty string "" as before. However, the latter refers to the
session/seat the client is in if that exists, with a fallback of the
user's display session if not. Clients can hence reference "auto"
instead of the empty string if they really don't want to think much
about sessions.

Why "self" btw? Previously, we'd already expose a special dbus object
with the path /org/freedesktop/login1/session/self (and similar for the
seat), matching what the empty string did for bus calls that took a
session name. With this scheme we reuse this identifier and introduce
"auto" in a similar way.

Of course this means real-life seats and sessions can never be named
"self" or "auto", but they aren't anyway: valid seat names have to start
with "seat" anyway, and sessions are generated server-side as either a
numeric value or "c" suffixed with a counter ID.

Fixes: #12399
  • Loading branch information
poettering committed May 24, 2019
1 parent 469df51 commit 3b92c08
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 87 deletions.
111 changes: 75 additions & 36 deletions src/login/logind-dbus.c
Expand Up @@ -46,47 +46,78 @@
#include "utmp-wtmp.h"
#include "virt.h"

static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) {
static int get_sender_session(
Manager *m,
sd_bus_message *message,
bool consult_display,
sd_bus_error *error,
Session **ret) {

_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
Session *session = NULL;
const char *name;
Session *session;
int r;

/* Get client login session. This is not what you are looking for these days,
* as apps may instead belong to a user service unit. This includes terminal
* emulators and hence command-line apps. */
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
/* Acquire the sender's session. This first checks if the sending process is inside a session itself,
* and returns that. If not and 'consult_display' is true, this returns the display session of the
* owning user of the caller. */

r = sd_bus_query_sender_creds(message,
SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT|
(consult_display ? SD_BUS_CREDS_OWNER_UID : 0), &creds);
if (r < 0)
return r;

r = sd_bus_creds_get_session(creds, &name);
if (r == -ENXIO)
goto err_no_session;
if (r < 0)
return r;
if (r < 0) {
if (r != -ENXIO)
return r;

if (consult_display) {
uid_t uid;

r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r < 0) {
if (r != -ENXIO)
return r;
} else {
User *user;

user = hashmap_get(m->users, UID_TO_PTR(uid));
if (user)
session = user->display;
}
}
} else
session = hashmap_get(m->sessions, name);

session = hashmap_get(m->sessions, name);
if (!session)
goto err_no_session;
return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
consult_display ?
"Caller does not belong to any known session and doesn't own any suitable session." :
"Caller does not belong to any known session.");

*ret = session;
return 0;

err_no_session:
return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
"Caller does not belong to any known session");
}

int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
int manager_get_session_from_creds(
Manager *m,
sd_bus_message *message,
const char *name,
sd_bus_error *error,
Session **ret) {

Session *session;

assert(m);
assert(message);
assert(ret);

if (isempty(name))
return get_sender_session(m, message, error, ret);
if (SEAT_IS_SELF(name)) /* the caller's own session */
return get_sender_session(m, message, false, error, ret);
if (SEAT_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */
return get_sender_session(m, message, true, error, ret);

session = hashmap_get(m->sessions, name);
if (!session)
Expand All @@ -97,7 +128,6 @@ int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const ch
}

static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *error, User **ret) {

_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
uid_t uid;
User *user;
Expand All @@ -109,21 +139,20 @@ static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *er
return r;

r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r == -ENXIO)
goto err_no_user;
if (r < 0)
return r;
if (r < 0) {
if (r != -ENXIO)
return r;

user = NULL;
} else
user = hashmap_get(m->users, UID_TO_PTR(uid));

user = hashmap_get(m->users, UID_TO_PTR(uid));
if (!user)
goto err_no_user;
return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
"Caller does not belong to any logged in or lingering user");

*ret = user;
return 0;

err_no_user:
return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
"Caller does not belong to any logged in user or lingering user");
}

int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
Expand All @@ -145,24 +174,31 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid,
return 0;
}

int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret) {
int manager_get_seat_from_creds(
Manager *m,
sd_bus_message *message,
const char *name,
sd_bus_error *error,
Seat **ret) {

Seat *seat;
int r;

assert(m);
assert(message);
assert(ret);

if (isempty(name)) {
if (SEAT_IS_SELF(name) || SEAT_IS_AUTO(name)) {
Session *session;

r = manager_get_session_from_creds(m, message, NULL, error, &session);
/* Use these special seat names as session names */
r = manager_get_session_from_creds(m, message, name, error, &session);
if (r < 0)
return r;

seat = session->seat;
if (!seat)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat.");
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session '%s' has no seat.", session->id);
} else {
seat = hashmap_get(m->seats, name);
if (!seat)
Expand Down Expand Up @@ -830,6 +866,10 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
} while (hashmap_get(m->sessions, id));
}

/* The generated names should not clash with 'auto' or 'self' */
assert(!SESSION_IS_SELF(id));
assert(!SESSION_IS_AUTO(id));

/* If we are not watching utmp already, try again */
manager_reconnect_utmp(m);

Expand Down Expand Up @@ -990,8 +1030,7 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda
assert(message);
assert(m);

/* Same as ActivateSession() but refuses to work if
* the seat doesn't match */
/* 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)
Expand Down
70 changes: 44 additions & 26 deletions src/login/logind-seat-dbus.c
Expand Up @@ -255,7 +255,10 @@ const sd_bus_vtable seat_vtable[] = {
};

int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *e = NULL;
sd_bus_message *message;
Manager *m = userdata;
const char *p;
Seat *seat;
int r;

Expand All @@ -265,32 +268,25 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
assert(found);
assert(m);

if (streq(path, "/org/freedesktop/login1/seat/self")) {
sd_bus_message *message;

message = sd_bus_get_current_message(bus);
if (!message)
return 0;

r = manager_get_seat_from_creds(m, message, NULL, error, &seat);
if (r < 0)
return r;
} else {
_cleanup_free_ char *e = NULL;
const char *p;
p = startswith(path, "/org/freedesktop/login1/seat/");
if (!p)
return 0;

p = startswith(path, "/org/freedesktop/login1/seat/");
if (!p)
return 0;
e = bus_label_unescape(p);
if (!e)
return -ENOMEM;

e = bus_label_unescape(p);
if (!e)
return -ENOMEM;
message = sd_bus_get_current_message(bus);
if (!message)
return 0;

seat = hashmap_get(m->seats, e);
if (!seat)
return 0;
r = manager_get_seat_from_creds(m, message, e, error, &seat);
if (r == -ENXIO) {
sd_bus_error_free(error);
return 0;
}
if (r < 0)
return r;

*found = seat;
return 1;
Expand Down Expand Up @@ -335,25 +331,47 @@ int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***
message = sd_bus_get_current_message(bus);
if (message) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *name;
Session *session;

r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
if (r >= 0) {
bool may_auto = false;
const char *name;

r = sd_bus_creds_get_session(creds, &name);
if (r >= 0) {
Session *session;

session = hashmap_get(m->sessions, name);
if (session && session->seat) {
r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
if (r < 0)
return r;

may_auto = true;
}
}

if (!may_auto) {
uid_t uid;

r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r >= 0) {
User *user;

user = hashmap_get(m->users, UID_TO_PTR(uid));
may_auto = user && user->display && user->display->seat;
}
}

if (may_auto) {
r = strv_extend(&l, "/org/freedesktop/login1/seat/auto");
if (r < 0)
return r;
}
}
}

*nodes = TAKE_PTR(l);

return 1;
}

Expand Down
8 changes: 8 additions & 0 deletions src/login/logind-seat.h
Expand Up @@ -77,3 +77,11 @@ int seat_send_signal(Seat *s, bool new_seat);
int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_;

int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);

static inline bool SEAT_IS_SELF(const char *name) {
return isempty(name) || streq(name, "self");
}

static inline bool SEAT_IS_AUTO(const char *name) {
return streq_ptr(name, "auto");
}

0 comments on commit 3b92c08

Please sign in to comment.