mirror of
https://github.com/systemd/systemd
synced 2024-07-21 18:24:38 +00:00
logind: add ability to upgrade session class from 'user-incomplete' to 'user'
This commit is contained in:
parent
249067d178
commit
6e9bf0ad29
|
@ -1202,7 +1202,6 @@ node /org/freedesktop/login1/session/1 {
|
|||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly u Audit = ...;
|
||||
readonly s Type = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s Class = '...';
|
||||
readonly b Active = ...;
|
||||
readonly s State = '...';
|
||||
|
|
|
@ -4038,22 +4038,26 @@ const BusObjectImplementation manager_object = {
|
|||
&user_object),
|
||||
};
|
||||
|
||||
static int session_jobs_reply(Session *s, uint32_t jid, const char *unit, const char *result) {
|
||||
static void session_jobs_reply(Session *s, uint32_t jid, const char *unit, const char *result) {
|
||||
assert(s);
|
||||
assert(unit);
|
||||
|
||||
if (!s->started)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (result && !streq(result, "done")) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
|
||||
|
||||
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED,
|
||||
"Job %u for unit '%s' failed with '%s'", jid, unit, result);
|
||||
return session_send_create_reply(s, &e);
|
||||
|
||||
(void) session_send_create_reply(s, &e);
|
||||
(void) session_send_upgrade_reply(s, &e);
|
||||
return;
|
||||
}
|
||||
|
||||
return session_send_create_reply(s, NULL);
|
||||
(void) session_send_create_reply(s, /* error= */ NULL);
|
||||
(void) session_send_upgrade_reply(s, /* error= */ NULL);
|
||||
}
|
||||
|
||||
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
|
@ -4089,7 +4093,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
|
|||
if (session) {
|
||||
if (streq_ptr(path, session->scope_job)) {
|
||||
session->scope_job = mfree(session->scope_job);
|
||||
(void) session_jobs_reply(session, id, unit, result);
|
||||
session_jobs_reply(session, id, unit, result);
|
||||
|
||||
session_save(session);
|
||||
user_save(session->user);
|
||||
|
@ -4106,7 +4110,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
|
|||
|
||||
LIST_FOREACH(sessions_by_user, s, user->sessions)
|
||||
/* Don't propagate user service failures to the client */
|
||||
(void) session_jobs_reply(s, id, unit, /* error = */ NULL);
|
||||
session_jobs_reply(s, id, unit, /* error = */ NULL /* don't propagate user service failures to the client */);
|
||||
|
||||
user_save(user);
|
||||
}
|
||||
|
|
|
@ -404,6 +404,62 @@ static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error
|
|||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int method_set_class(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
Session *s = ASSERT_PTR(userdata);
|
||||
SessionClass class;
|
||||
const char *c;
|
||||
uid_t uid;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = session_class_from_string(c);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid session class '%s'", c);
|
||||
|
||||
/* For now, we'll allow only upgrades user-incomplete → user */
|
||||
if (class != SESSION_USER)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Class may only be set to 'user', refusing.");
|
||||
if (s->class == SESSION_USER) /* No change, shortcut */
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
if (s->class != SESSION_USER_INCOMPLETE)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Only sessions with class 'user-incomplete' may change class, refusing.");
|
||||
|
||||
if (s->upgrade_message)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Set session class operation already in progress, refsuing.");
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_euid(creds, &uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (uid != 0 && uid != s->user->user_record->uid)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change its class");
|
||||
|
||||
session_set_class(s, class);
|
||||
|
||||
sd_bus_message_unref(s->upgrade_message);
|
||||
s->upgrade_message = sd_bus_message_ref(message);
|
||||
|
||||
r = session_send_upgrade_reply(s, /* error= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int method_set_display(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Session *s = ASSERT_PTR(userdata);
|
||||
const char *display;
|
||||
|
@ -875,6 +931,25 @@ int session_send_create_reply(Session *s, sd_bus_error *error) {
|
|||
false);
|
||||
}
|
||||
|
||||
int session_send_upgrade_reply(Session *s, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
|
||||
assert(s);
|
||||
|
||||
if (!s->upgrade_message)
|
||||
return 0;
|
||||
|
||||
if (!sd_bus_error_is_set(error) && !session_ready(s))
|
||||
return 0;
|
||||
|
||||
c = TAKE_PTR(s->upgrade_message);
|
||||
if (error)
|
||||
return sd_bus_reply_method_error(c, error);
|
||||
|
||||
session_save(s);
|
||||
|
||||
return sd_bus_reply_method_return(c, NULL);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable session_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
|
||||
|
@ -895,7 +970,7 @@ static const sd_bus_vtable session_vtable[] = {
|
|||
SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
|
@ -953,6 +1028,11 @@ static const sd_bus_vtable session_vtable[] = {
|
|||
SD_BUS_NO_RESULT,
|
||||
method_set_type,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("SetClass",
|
||||
SD_BUS_ARGS("s", class),
|
||||
SD_BUS_NO_RESULT,
|
||||
method_set_class,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("SetDisplay",
|
||||
SD_BUS_ARGS("s", display),
|
||||
SD_BUS_NO_RESULT,
|
||||
|
|
|
@ -16,6 +16,7 @@ int session_send_lock(Session *s, bool lock);
|
|||
int session_send_lock_all(Manager *m, bool lock);
|
||||
|
||||
int session_send_create_reply(Session *s, sd_bus_error *error);
|
||||
int session_send_upgrade_reply(Session *s, sd_bus_error *error);
|
||||
|
||||
int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
|
|
@ -187,6 +187,7 @@ Session* session_free(Session *s) {
|
|||
session_reset_leader(s, /* keep_fdstore = */ true);
|
||||
|
||||
sd_bus_message_unref(s->create_message);
|
||||
sd_bus_message_unref(s->upgrade_message);
|
||||
|
||||
free(s->tty);
|
||||
free(s->display);
|
||||
|
@ -1210,6 +1211,20 @@ void session_set_type(Session *s, SessionType t) {
|
|||
(void) session_send_changed(s, "Type", NULL);
|
||||
}
|
||||
|
||||
void session_set_class(Session *s, SessionClass c) {
|
||||
assert(s);
|
||||
|
||||
if (s->class == c)
|
||||
return;
|
||||
|
||||
s->class = c;
|
||||
(void) session_save(s);
|
||||
(void) session_send_changed(s, "Class", NULL);
|
||||
|
||||
/* This class change might mean we need the per-user session manager now. Try to start it */
|
||||
user_start_service_manager(s->user);
|
||||
}
|
||||
|
||||
int session_set_display(Session *s, const char *display) {
|
||||
int r;
|
||||
|
||||
|
|
|
@ -146,7 +146,8 @@ struct Session {
|
|||
|
||||
bool was_active:1;
|
||||
|
||||
sd_bus_message *create_message;
|
||||
sd_bus_message *create_message; /* The D-Bus message used to create the session, which we haven't responded to yet */
|
||||
sd_bus_message *upgrade_message; /* The D-Bus message used to upgrade the session class user-incomplete → user, wich we haven't responded to yet */
|
||||
|
||||
/* Set up when a client requested to release the session via the bus */
|
||||
sd_event_source *timer_event_source;
|
||||
|
@ -179,6 +180,7 @@ int session_set_idle_hint(Session *s, bool b);
|
|||
int session_get_locked_hint(Session *s);
|
||||
int session_set_locked_hint(Session *s, bool b);
|
||||
void session_set_type(Session *s, SessionType t);
|
||||
void session_set_class(Session *s, SessionClass c);
|
||||
int session_set_display(Session *s, const char *display);
|
||||
int session_set_tty(Session *s, const char *tty);
|
||||
int session_create_fifo(Session *s);
|
||||
|
|
|
@ -334,6 +334,10 @@
|
|||
send_interface="org.freedesktop.login1.Session"
|
||||
send_member="SetType"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.login1"
|
||||
send_interface="org.freedesktop.login1.Session"
|
||||
send_member="SetClass"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.login1"
|
||||
send_interface="org.freedesktop.login1.Session"
|
||||
send_member="TakeDevice"/>
|
||||
|
|
Loading…
Reference in a new issue