#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)
}
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;
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) {
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(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)
} 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);
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)