Skip to content

Commit

Permalink
logind: introduce CreateSessionWithPIDFD()
Browse files Browse the repository at this point in the history
This new D-Bus API uses pidfd to refer to the session leader. Also,
pam_systemd will try to make use of it when pidfd support is available.
  • Loading branch information
msekletar authored and bluca committed Oct 26, 2023
1 parent c895d04 commit 76f2191
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 99 deletions.
37 changes: 32 additions & 5 deletions man/org.freedesktop.login1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,30 @@ node /org/freedesktop/login1 {
out u vtnr,
out b existing);
@org.freedesktop.systemd1.Privileged("true")
CreateSessionWithPIDFD(in u uid,
in h pidfd,
in s service,
in s type,
in s class,
in s desktop,
in s seat_id,
in u vtnr,
in s tty,
in s display,
in b remote,
in s remote_user,
in s remote_host,
in t flags,
in a(sv) properties,
out s session_id,
out o object_path,
out s runtime_path,
out h fifo_fd,
out u uid,
out s seat_id,
out u vtnr,
out b existing);
@org.freedesktop.systemd1.Privileged("true")
ReleaseSession(in s session_id);
ActivateSession(in s session_id);
ActivateSessionOnSeat(in s session_id,
Expand Down Expand Up @@ -294,6 +318,8 @@ node /org/freedesktop/login1 {

<variablelist class="dbus-method" generated="True" extra-ref="CreateSession()"/>

<variablelist class="dbus-method" generated="True" extra-ref="CreateSessionWithPIDFD()"/>

<variablelist class="dbus-method" generated="True" extra-ref="ReleaseSession()"/>

<variablelist class="dbus-method" generated="True" extra-ref="ActivateSession()"/>
Expand Down Expand Up @@ -525,10 +551,10 @@ node /org/freedesktop/login1 {
structures consisting of <varname>what</varname>, <varname>who</varname>, <varname>why</varname>,
<varname>mode</varname>, <varname>uid</varname> (user ID), and <varname>pid</varname> (process ID).</para>

<para><function>CreateSession()</function> and <function>ReleaseSession()</function> may be used to
open or close login sessions. These calls should <emphasis>never</emphasis> be invoked directly by
clients. Creating/closing sessions is exclusively the job of PAM and its
<citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<para><function>CreateSession()</function>, <function>CreateSessionWithPIDFD()</function>, and
<function>ReleaseSession()</function> may be used to open or close login sessions. These calls should
<emphasis>never</emphasis> be invoked directly by clients. Creating/closing sessions is exclusively the job
of PAM and its <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
module.</para>

<para><function>ActivateSession()</function> brings the session with the specified ID into the
Expand Down Expand Up @@ -1520,7 +1546,8 @@ node /org/freedesktop/login1/session/1 {
<varname>HandleSuspendKeyLongPress</varname>, and
<varname>HandleHibernateKeyLongPress</varname> were added in version 251.</para>
<para><varname>StopIdleSessionUSec</varname> was added in version 252.</para>
<para><function>PrepareForShutdownWithMetadata</function> was added in version 255.</para>
<para><function>PrepareForShutdownWithMetadata</function> and
<function>CreateSessionWithPIDFD()</function> were added in version 255.</para>
</refsect2>
<refsect2>
<title>Session Objects</title>
Expand Down
216 changes: 184 additions & 32 deletions src/login/logind-dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,36 +677,73 @@ static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bu
return sd_bus_send(NULL, reply, NULL);
}

static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
static int create_session(
sd_bus_message *message,
void *userdata,
sd_bus_error *error,
uid_t uid,
pid_t pid,
int pidfd,
const char *service,
const char *type,
const char *class,
const char *desktop,
const char *cseat,
uint32_t vtnr,
const char *tty,
const char *display,
int remote,
const char *remote_user,
const char *remote_host,
uint64_t flags) {

_cleanup_(pidref_done) PidRef leader = PIDREF_NULL;
Manager *m = ASSERT_PTR(userdata);
_cleanup_free_ char *id = NULL;
Session *session = NULL;
uint32_t audit_id = 0;
Manager *m = ASSERT_PTR(userdata);
User *user = NULL;
Seat *seat = NULL;
pid_t leader;
uid_t uid;
int remote;
uint32_t vtnr = 0;
SessionType t;
SessionClass c;
int r;

assert(message);

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);
if (r < 0)
return r;

if (!uid_is_valid(uid))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
if (leader < 0 || leader == 1 || leader == getpid_cached())

if (flags != 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero.");

if (pidfd >= 0) {
r = pidref_set_pidfd(&leader, pidfd);
if (r < 0)
return r;
} else if (pid == 0) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
pid_t p;

r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
if (r < 0)
return r;

r = sd_bus_creds_get_pid(creds, &p);
if (r < 0)
return r;

r = pidref_set_pid(&leader, p);
if (r < 0)
return r;
} else {
assert(pid > 0);

r = pidref_set_pid(&leader, pid);
if (r < 0)
return r;
}

if (leader.pid == 1 || leader.pid == getpid_cached())
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");

if (isempty(type))
Expand Down Expand Up @@ -805,21 +842,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
c = SESSION_USER;
}

if (leader == 0) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;

r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
if (r < 0)
return r;

r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
if (r < 0)
return r;
}

/* Check if we are already in a logind session. Or if we are in [email protected]
* which is a special PAM session that avoids creating a logind session. */
r = manager_get_user_by_pid(m, leader, NULL);
r = manager_get_user_by_pid(m, leader.pid, NULL);
if (r < 0)
return r;
if (r > 0)
Expand Down Expand Up @@ -848,7 +873,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
"Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.",
m->sessions_max);

(void) audit_session_from_pid(leader, &audit_id);
(void) audit_session_from_pid(leader.pid, &audit_id);
if (audit_session_is_valid(audit_id)) {
/* Keep our session IDs and the audit session IDs in sync */

Expand Down Expand Up @@ -890,7 +915,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
goto fail;

session_set_user(session, user);
r = session_set_leader(session, leader);
r = session_set_leader_consume(session, TAKE_PIDREF(leader));
if (r < 0)
goto fail;

Expand Down Expand Up @@ -984,6 +1009,107 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
return r;
}

static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
pid_t leader;
uid_t uid;
int remote;
uint32_t vtnr = 0;
int r;

assert(message);

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);
if (r < 0)
return r;

return create_session(
message,
userdata,
error,
uid,
leader,
/* pidfd = */ -EBADF,
service,
type,
class,
desktop,
cseat,
vtnr,
tty,
display,
remote,
remote_user,
remote_host,
/* flags = */ 0);
}

static int method_create_session_pidfd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
int leaderfd = -EBADF;
uid_t uid;
int remote;
uint32_t vtnr = 0;
uint64_t flags;
int r;

r = sd_bus_message_read(message,
"uhsssssussbsst",
&uid,
&leaderfd,
&service,
&type,
&class,
&desktop,
&cseat,
&vtnr,
&tty,
&display,
&remote,
&remote_user,
&remote_host,
&flags);
if (r < 0)
return r;

return create_session(
message,
userdata,
error,
uid,
/* pid = */ 0,
leaderfd,
service,
type,
class,
desktop,
cseat,
vtnr,
tty,
display,
remote,
remote_user,
remote_host,
flags);
}

static int method_release_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
Session *session;
Expand Down Expand Up @@ -3494,6 +3620,32 @@ static const sd_bus_vtable manager_vtable[] = {
"b", existing),
method_create_session,
0),
SD_BUS_METHOD_WITH_ARGS("CreateSessionWithPIDFD",
SD_BUS_ARGS("u", uid,
"h", pidfd,
"s", service,
"s", type,
"s", class,
"s", desktop,
"s", seat_id,
"u", vtnr,
"s", tty,
"s", display,
"b", remote,
"s", remote_user,
"s", remote_host,
"t", flags,
"a(sv)", properties),
SD_BUS_RESULT("s", session_id,
"o", object_path,
"s", runtime_path,
"h", fifo_fd,
"u", uid,
"s", seat_id,
"u", vtnr,
"b", existing),
method_create_session_pidfd,
0),
SD_BUS_METHOD_WITH_ARGS("ReleaseSession",
SD_BUS_ARGS("s", session_id),
SD_BUS_NO_RESULT,
Expand Down
5 changes: 5 additions & 0 deletions src/login/logind-session-dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,7 @@ int session_send_create_reply(Session *s, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
_cleanup_close_ int fifo_fd = -EBADF;
_cleanup_free_ char *p = NULL;
int r;

assert(s);

Expand All @@ -830,6 +831,10 @@ int session_send_create_reply(Session *s, sd_bus_error *error) {
if (fifo_fd < 0)
return fifo_fd;

r = session_watch_pidfd(s);
if (r < 0)
return r;

/* Update the session state file before we notify the client about the result. */
session_save(s);

Expand Down
Loading

0 comments on commit 76f2191

Please sign in to comment.