X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Flogin%2Flogind-dbus.c;h=0e8925ab9449a29d7facea68a354e657345163e3;hb=4b381a9ef65d68dc79760b093436a9c81f43fa5d;hp=e8d40ab185c4b81f060a4602eaec95db22293fa1;hpb=d923021aebc6aa0d5f550f69a27f431d128180ba;p=thirdparty%2Fsystemd.git diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index e8d40ab185c..0e8925ab944 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -27,6 +27,10 @@ #include "fileio.h" #include "format-util.h" #include "fs-util.h" +#include "logind-dbus.h" +#include "logind-seat-dbus.h" +#include "logind-session-dbus.h" +#include "logind-user-dbus.h" #include "logind.h" #include "missing_capability.h" #include "mkdir.h" @@ -46,47 +50,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) @@ -97,7 +132,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; @@ -109,20 +143,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) { @@ -137,13 +171,20 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, user = hashmap_get(m->users, UID_TO_PTR(uid)); if (!user) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "User ID "UID_FMT" is not logged in or lingering", uid); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, + "User ID "UID_FMT" is not logged in or lingering", uid); *ret = user; 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; @@ -151,16 +192,17 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char 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) @@ -371,7 +413,8 @@ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd return r; if (!session) - return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID "PID_FMT" does not belong to any known session", pid); + return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, + "PID "PID_FMT" does not belong to any known session", pid); } p = session_bus_path(session); @@ -649,7 +692,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus assert_cc(sizeof(pid_t) == sizeof(uint32_t)); assert_cc(sizeof(uid_t) == sizeof(uint32_t)); - r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host); + r = sd_bus_message_read(message, "uusssssussbss", + &uid, &leader, &service, &type, &class, &desktop, &cseat, + &vtnr, &tty, &display, &remote, &remote_user, &remote_host); if (r < 0) return r; @@ -663,7 +708,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus else { t = session_type_from_string(type); if (t < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid session type %s", type); } if (isempty(class)) @@ -671,14 +717,16 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus else { c = session_class_from_string(class); if (c < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid session class %s", class); } if (isempty(desktop)) desktop = NULL; else { if (!string_is_safe(desktop)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid desktop string %s", desktop); } if (isempty(cseat)) @@ -686,7 +734,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus else { seat = hashmap_get(m->seats, cseat); if (!seat) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, + "No seat '%s' known", cseat); } if (tty_is_vc(tty)) { @@ -695,35 +744,42 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus if (!seat) seat = m->seat0; else if (seat != m->seat0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat->id); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "TTY %s is virtual console but seat %s is not seat0", tty, seat->id); v = vtnr_from_tty(tty); if (v <= 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Cannot determine VT number from virtual console TTY %s", tty); if (vtnr == 0) vtnr = (uint32_t) v; else if (vtnr != (uint32_t) v) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Specified TTY and VT number do not match"); } else if (tty_is_console(tty)) { if (!seat) seat = m->seat0; else if (seat != m->seat0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Console TTY specified but seat is not seat0"); if (vtnr != 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Console TTY specified but VT number is not 0"); } if (seat) { if (seat_has_vts(seat)) { if (vtnr <= 0 || vtnr > 63) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "VT number out of range"); } else { if (vtnr != 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Seat has no VTs but VT number not 0"); } } @@ -755,13 +811,14 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus return r; } - /* Check if we are already in a logind session. Or if we are in user@.service which is a special PAM session - * that avoids creating a logind session. */ + /* Check if we are already in a logind session. Or if we are in user@.service + * which is a special PAM session that avoids creating a logind session. */ r = manager_get_user_by_pid(m, leader, NULL); if (r < 0) return r; if (r > 0) - return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice"); + return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, + "Already running in a session or user slice"); /* * Old gdm and lightdm start the user-session on the same VT as @@ -781,7 +838,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session"); if (hashmap_size(m->sessions) >= m->sessions_max) - return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max); + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, + "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", + m->sessions_max); (void) audit_session_from_pid(leader, &audit_id); if (audit_session_is_valid(audit_id)) { @@ -790,11 +849,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus if (asprintf(&id, "%"PRIu32, audit_id) < 0) return -ENOMEM; - /* Wut? There's already a session by this name and we - * didn't find it above? Weird, then let's not trust - * the audit data and let's better register a new - * ID */ - if (hashmap_get(m->sessions, id)) { + /* Wut? There's already a session by this name and we didn't find it above? Weird, then let's + * not trust the audit data and let's better register a new ID */ + if (hashmap_contains(m->sessions, id)) { log_warning("Existing logind session ID %s used by new audit session, ignoring.", id); audit_id = AUDIT_SESSION_INVALID; id = mfree(id); @@ -808,10 +865,14 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus if (asprintf(&id, "c%lu", ++m->session_counter) < 0) return -ENOMEM; - } while (hashmap_get(m->sessions, id)); + } while (hashmap_contains(m->sessions, id)); } - /* If we are not watching utmp aleady, try again */ + /* 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); r = manager_add_user_by_uid(m, uid, &user); @@ -971,8 +1032,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) @@ -987,7 +1047,8 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda return r; if (session->seat != seat) - return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name); + return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, + "Session %s not on seat %s", session_name, seat_name); r = session_activate(session); if (r < 0) @@ -1347,11 +1408,22 @@ static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_ if (r < 0) return r; + if (!path_is_normalized(sysfs)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", sysfs); if (!path_startswith(sysfs, "/sys")) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs); - if (!seat_name_is_valid(seat)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat); + if (SEAT_IS_SELF(seat) || SEAT_IS_AUTO(seat)) { + Seat *found; + + r = manager_get_seat_from_creds(m, message, seat, error, &found); + if (r < 0) + return r; + + seat = found->id; + + } else if (!seat_name_is_valid(seat)) /* Note that a seat does not have to exist yet for this operation to succeed */ + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat name %s is not valid", seat); r = bus_verify_polkit_async( message, @@ -1795,7 +1867,8 @@ static int method_do_shutdown_or_sleep( /* Don't allow multiple jobs being executed at the same time */ if (m->action_what > 0) - return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress"); + return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, + "There's already a shutdown or sleep operation in progress"); if (sleep_verb) { r = can_sleep(sleep_verb); @@ -3127,22 +3200,26 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error w = inhibit_what_from_string(what); if (w <= 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid what specification %s", what); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid what specification %s", what); mm = inhibit_mode_from_string(mode); if (mm < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid mode specification %s", mode); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid mode specification %s", mode); /* Delay is only supported for shutdown/sleep */ if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Delay inhibitors only supported for shutdown and sleep"); /* Don't allow taking delay locks while we are already * executing the operation. We shouldn't create the impression * that the lock was successful if the machine is about to go * down/suspend any moment. */ if (m->action_what & w) - return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running"); + return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, + "The operation inhibition has been requested for is already running"); r = bus_verify_polkit_async( message, @@ -3177,7 +3254,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error return r; if (hashmap_size(m->inhibitors) >= m->inhibitors_max) - return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max); + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, + "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", + m->inhibitors_max); do { id = mfree(id); @@ -3339,7 +3418,8 @@ static int session_jobs_reply(Session *s, const char *unit, const char *result) 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, "Start job for unit '%s' failed with '%s'", unit, result); + sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, + "Start job for unit '%s' failed with '%s'", unit, result); return session_send_create_reply(s, &e); }