use anyhow::{Context as _, Result};
use zbus::zvariant::{OwnedFd, OwnedObjectPath, Value};
type CreateSessionReply = (
String,
OwnedObjectPath,
String,
OwnedFd,
u32,
String,
u32,
bool,
);
#[zbus::proxy(
interface = "org.freedesktop.login1.Manager",
default_service = "org.freedesktop.login1",
default_path = "/org/freedesktop/login1"
)]
trait Manager {
#[allow(clippy::too_many_arguments)]
fn create_session(
&self,
uid: u32,
leader_pid: u32,
service: &str,
session_type: &str,
class: &str,
desktop: &str,
seat_id: &str,
vtnr: u32,
tty: &str,
display: &str,
remote: bool,
remote_user: &str,
remote_host: &str,
properties: &[(&str, Value<'_>)],
) -> zbus::Result<CreateSessionReply>;
}
pub(crate) struct LogindSession {
pub(crate) session_id: String,
pub(crate) runtime_path: String,
_fifo: OwnedFd,
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub(crate) fn create_session(
uid: u32,
leader_pid: u32,
tty: &str,
remote_host: Option<&str>,
) -> Result<LogindSession> {
let connection = zbus::blocking::Connection::system().context("connect to system D-Bus bus")?;
let manager = ManagerProxyBlocking::new(&connection).context("build login1 manager proxy")?;
let remote = remote_host.is_some();
let remote_host = remote_host.unwrap_or("");
let no_properties: &[(&str, Value<'_>)] = &[];
let (session_id, _object_path, runtime_path, fifo, _uid, _seat, _vtnr, _existing) = manager
.create_session(
uid,
leader_pid,
"mps",
"tty",
"user",
"",
"",
0,
tty,
"",
remote,
"",
remote_host,
no_properties,
)
.context("logind CreateSession failed")?;
Ok(LogindSession {
session_id,
runtime_path,
_fifo: fifo,
})
}
#[cfg(test)]
mod test {
use super::create_session;
#[test]
#[allow(unsafe_code)]
fn create_session_errors_without_bus() {
unsafe {
std::env::set_var(
"DBUS_SYSTEM_BUS_ADDRESS",
"unix:path=/nonexistent/moshpit-logind-test",
);
}
let result = create_session(0, 0, "pts/test", Some("203.0.113.1"));
assert!(result.is_err());
}
}