walld: implement polkit auth
This commit is contained in:
Generated
+227
-8
@@ -56,7 +56,7 @@ version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -67,7 +67,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -118,6 +118,28 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
@@ -346,6 +368,33 @@ version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
|
||||
dependencies = [
|
||||
"enumflags2_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -359,7 +408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -576,6 +625,12 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.65"
|
||||
@@ -849,7 +904,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -888,6 +943,16 @@ version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_display"
|
||||
version = "0.1.4"
|
||||
@@ -968,6 +1033,15 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
@@ -1040,6 +1114,7 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
"users",
|
||||
"uucore",
|
||||
"zbus",
|
||||
"zlink",
|
||||
]
|
||||
|
||||
@@ -1059,7 +1134,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1132,6 +1207,17 @@ dependencies = [
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.1.1"
|
||||
@@ -1191,7 +1277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1232,7 +1318,7 @@ dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1242,7 +1328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1394,6 +1480,18 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.25.13+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow 1.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
@@ -1490,6 +1588,17 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid"
|
||||
version = "0.9.6"
|
||||
@@ -1568,6 +1677,17 @@ dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde_core",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
@@ -1787,6 +1907,65 @@ name = "winnow"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe18fb60dc696039e738717b76eaea21e7a4489bbb1885020b43c94236d7e98a"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-lite",
|
||||
"hex",
|
||||
"libc",
|
||||
"ordered-stream",
|
||||
"rustix",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"uuid",
|
||||
"windows-sys 0.61.2",
|
||||
"winnow 1.0.4",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "4.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow 1.0.4",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
@@ -1888,3 +2067,43 @@ name = "zmij"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bee2a0bcd2a907786a456fff45aaaaf54c9ba5f50b71ae9ec1a4edd200c94911"
|
||||
dependencies = [
|
||||
"endi",
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"winnow 1.0.4",
|
||||
"zvariant_derive",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "5.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_utils"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90cb9383f9b45290407a1258b202d3f8f01db719eb60b4e4055c6375af4fc7c7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.119",
|
||||
"winnow 1.0.4",
|
||||
]
|
||||
|
||||
@@ -43,6 +43,7 @@ netlink-proto = "0.12.0"
|
||||
netlink-sys = { version = "0.8.8", features = ["tokio_socket"] }
|
||||
netlink-packet-audit = "0.6.1"
|
||||
thiserror = "2.0.19"
|
||||
zbus = { version = "5.18.0", default-features = false, features = ["tokio"] }
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "2.0.7"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod config;
|
||||
pub mod fingerd;
|
||||
pub mod ignore_list;
|
||||
pub mod polkit;
|
||||
pub mod rwhod;
|
||||
pub mod varlink_api;
|
||||
pub mod walld;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
//! polkit authorization checks against `org.freedesktop.PolicyKit1.Authority`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Context;
|
||||
use zbus::{Connection, proxy, zvariant::Value};
|
||||
|
||||
#[proxy(
|
||||
default_service = "org.freedesktop.PolicyKit1",
|
||||
default_path = "/org/freedesktop/PolicyKit1/Authority",
|
||||
interface = "org.freedesktop.PolicyKit1.Authority"
|
||||
)]
|
||||
trait Authority {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn check_authorization(
|
||||
&self,
|
||||
subject: &(&str, HashMap<&str, Value<'_>>),
|
||||
action_id: &str,
|
||||
details: &HashMap<&str, &str>,
|
||||
flags: u32,
|
||||
cancellation_id: &str,
|
||||
) -> zbus::Result<(bool, bool, HashMap<String, String>)>;
|
||||
}
|
||||
|
||||
#[proxy(
|
||||
default_service = "org.freedesktop.login1",
|
||||
default_path = "/org/freedesktop/login1",
|
||||
interface = "org.freedesktop.login1.Manager"
|
||||
)]
|
||||
trait LoginManager {
|
||||
#[zbus(name = "GetSessionByPID")]
|
||||
fn get_session_by_pid(&self, pid: u32) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
|
||||
}
|
||||
|
||||
#[proxy(interface = "org.freedesktop.login1.Session")]
|
||||
trait LoginSession {
|
||||
#[zbus(property)]
|
||||
fn id(&self) -> zbus::Result<String>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PolkitAuthority {
|
||||
connection: Connection,
|
||||
}
|
||||
|
||||
impl PolkitAuthority {
|
||||
pub async fn connect() -> anyhow::Result<Self> {
|
||||
let connection = Connection::system()
|
||||
.await
|
||||
.context("failed to connect to the D-Bus system bus")?;
|
||||
Ok(Self { connection })
|
||||
}
|
||||
|
||||
pub fn connection(&self) -> &Connection {
|
||||
&self.connection
|
||||
}
|
||||
|
||||
/// Resolve `pid`'s logind session id, if it has one.
|
||||
async fn session_id_for_pid(&self, pid: u32) -> Option<String> {
|
||||
let manager = LoginManagerProxy::new(&self.connection).await.ok()?;
|
||||
let path = manager.get_session_by_pid(pid).await.ok()?;
|
||||
let session = LoginSessionProxy::builder(&self.connection)
|
||||
.path(path)
|
||||
.ok()?
|
||||
.build()
|
||||
.await
|
||||
.ok()?;
|
||||
session.id().await.ok()
|
||||
}
|
||||
|
||||
/// Build a polkit subject for `pid`, using details from `logind` if possible.
|
||||
async fn subject(
|
||||
&self,
|
||||
pid: u32,
|
||||
) -> anyhow::Result<(&'static str, HashMap<&'static str, Value<'_>>)> {
|
||||
if let Some(session_id) = self.session_id_for_pid(pid).await {
|
||||
let mut details = HashMap::new();
|
||||
details.insert("session-id", Value::from(session_id));
|
||||
return Ok(("unix-session", details));
|
||||
}
|
||||
|
||||
let start_time = process_start_time(pid)?;
|
||||
let mut details = HashMap::new();
|
||||
details.insert("pid", Value::from(pid));
|
||||
details.insert("start-time", Value::from(start_time));
|
||||
Ok(("unix-process", details))
|
||||
}
|
||||
|
||||
/// Ask polkit whether `pid` is authorized to perform `action_id`
|
||||
pub(crate) async fn check(
|
||||
&self,
|
||||
pid: u32,
|
||||
action_id: &str,
|
||||
details: HashMap<&str, &str>,
|
||||
) -> anyhow::Result<bool> {
|
||||
let proxy = AuthorityProxy::new(&self.connection)
|
||||
.await
|
||||
.context("failed to build polkit Authority proxy")?;
|
||||
|
||||
let subject = self.subject(pid).await?;
|
||||
|
||||
let (authorized, _interactive, _details) = proxy
|
||||
.check_authorization(&subject, action_id, &details, 0, "")
|
||||
.await
|
||||
.context("CheckAuthorization call failed")?;
|
||||
|
||||
Ok(authorized)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a process's start time from `/proc/<pid>/stat`
|
||||
fn process_start_time(pid: u32) -> anyhow::Result<u64> {
|
||||
let stat = std::fs::read_to_string(format!("/proc/{pid}/stat"))
|
||||
.with_context(|| format!("failed to read /proc/{pid}/stat"))?;
|
||||
|
||||
let after_comm = stat
|
||||
.rsplit_once(')')
|
||||
.with_context(|| format!("malformed /proc/{pid}/stat"))?
|
||||
.1;
|
||||
|
||||
// starttime is field 22; index 19 once `state` (field 3) is index 0.
|
||||
after_comm
|
||||
.split_whitespace()
|
||||
.nth(19)
|
||||
.with_context(|| format!("missing starttime field in /proc/{pid}/stat"))?
|
||||
.parse::<u64>()
|
||||
.context("starttime field is not a valid number")
|
||||
}
|
||||
@@ -13,7 +13,7 @@ use zlink::{
|
||||
tokio::unix::{Listener as UnixListener, Stream as UnixStream},
|
||||
};
|
||||
|
||||
use crate::server::{ignore_list::IgnoreList, rwhod::RwhodStatusStore};
|
||||
use crate::server::{ignore_list::IgnoreList, polkit::PolkitAuthority, rwhod::RwhodStatusStore};
|
||||
|
||||
pub use crate::server::varlink_api::{fingerd::*, rwhod::*, walld::*};
|
||||
|
||||
@@ -46,12 +46,13 @@ pub enum VarlinkReplyError {
|
||||
Walld(VarlinkWalldClientError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct VarlinkRoowhoo2ClientServer {
|
||||
whod_status_store: RwhodStatusStore,
|
||||
rwhod_enabled: bool,
|
||||
fingerd_enabled: bool,
|
||||
finger_ignore_list: Option<IgnoreList>,
|
||||
polkit: Option<PolkitAuthority>,
|
||||
}
|
||||
|
||||
impl VarlinkRoowhoo2ClientServer {
|
||||
@@ -60,12 +61,14 @@ impl VarlinkRoowhoo2ClientServer {
|
||||
rwhod_enabled: bool,
|
||||
fingerd_enabled: bool,
|
||||
finger_ignore_list: Option<IgnoreList>,
|
||||
polkit: Option<PolkitAuthority>,
|
||||
) -> Self {
|
||||
Self {
|
||||
whod_status_store,
|
||||
rwhod_enabled,
|
||||
fingerd_enabled,
|
||||
finger_ignore_list,
|
||||
polkit,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,6 +286,7 @@ impl zlink::Service<UnixStream> for VarlinkRoowhoo2ClientServer {
|
||||
let result = match timeout(
|
||||
Duration::from_secs(2),
|
||||
handle_wall_request(
|
||||
self.polkit.as_ref(),
|
||||
peer_pid,
|
||||
peer_uid,
|
||||
source_tty.clone(),
|
||||
@@ -329,6 +333,7 @@ impl zlink::Service<UnixStream> for VarlinkRoowhoo2ClientServer {
|
||||
let result = match timeout(
|
||||
Duration::from_secs(2),
|
||||
handle_write_request(
|
||||
self.polkit.as_ref(),
|
||||
peer_pid,
|
||||
peer_uid,
|
||||
source_tty.clone(),
|
||||
@@ -375,11 +380,28 @@ pub async fn varlink_client_server_task(
|
||||
fingerd_enabled: bool,
|
||||
finger_ignore_list: Option<IgnoreList>,
|
||||
) -> anyhow::Result<()> {
|
||||
let polkit = match timeout(Duration::from_secs(5), PolkitAuthority::connect()).await {
|
||||
Ok(Ok(polkit)) => Some(polkit),
|
||||
Ok(Err(e)) => {
|
||||
tracing::warn!(
|
||||
"Failed to connect to polkit; Wall/Write requests will be denied: {e:#}"
|
||||
);
|
||||
None
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::warn!(
|
||||
"Timed out connecting to polkit after 5 seconds; Wall/Write requests will be denied"
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let service = VarlinkRoowhoo2ClientServer::new(
|
||||
whod_status_store,
|
||||
rwhod_enabled,
|
||||
fingerd_enabled,
|
||||
finger_ignore_list,
|
||||
polkit,
|
||||
);
|
||||
|
||||
let server = zlink::Server::new(socket, service);
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::time::Duration;
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use nix::unistd::gethostname;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zlink::ReplyError;
|
||||
|
||||
use crate::server::walld::tty_utils::{self, TtyError};
|
||||
use crate::server::{
|
||||
polkit::PolkitAuthority,
|
||||
walld::tty_utils::{self, TtyError},
|
||||
};
|
||||
|
||||
#[zlink::proxy("no.ntnu.pvv.roowho2.walld")]
|
||||
pub trait VarlinkWalldClientProxy {
|
||||
@@ -162,11 +165,65 @@ fn tty_error_to_walld_error(user: &str, tty: &str, err: TtyError) -> VarlinkWall
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: have the client send the name of the TTY
|
||||
// verify that the TTY is owned by the user from peercred.
|
||||
const POLKIT_ACTION_WALL: &str = "no.ntnu.pvv.roowho2.wall";
|
||||
const POLKIT_ACTION_WRITE: &str = "no.ntnu.pvv.roowho2.write";
|
||||
|
||||
/// Check whether `pid` is allowed to broadcast a `wall` message, optionally restricted to `group`.
|
||||
async fn check_wall(
|
||||
polkit: &PolkitAuthority,
|
||||
pid: u32,
|
||||
group: Option<&str>,
|
||||
) -> anyhow::Result<bool> {
|
||||
let mut details = HashMap::new();
|
||||
if let Some(group) = group {
|
||||
details.insert("group", group);
|
||||
}
|
||||
polkit.check(pid, POLKIT_ACTION_WALL, details).await
|
||||
}
|
||||
|
||||
/// Check whether `pid` is allowed to `write` to `user`, optionally on a specific `tty`.
|
||||
async fn check_write(
|
||||
polkit: &PolkitAuthority,
|
||||
pid: u32,
|
||||
user: &str,
|
||||
tty: Option<&str>,
|
||||
) -> anyhow::Result<bool> {
|
||||
let mut details = HashMap::new();
|
||||
details.insert("user", user);
|
||||
if let Some(tty) = tty {
|
||||
details.insert("tty", tty);
|
||||
}
|
||||
polkit.check(pid, POLKIT_ACTION_WRITE, details).await
|
||||
}
|
||||
|
||||
/// Wrapper doing some basic error handling against a polkit check.
|
||||
async fn authorize<'a, F, Fut>(
|
||||
polkit: Option<&'a PolkitAuthority>,
|
||||
check: F,
|
||||
) -> Result<(), VarlinkWalldClientError>
|
||||
where
|
||||
F: FnOnce(&'a PolkitAuthority) -> Fut,
|
||||
Fut: std::future::Future<Output = anyhow::Result<bool>>,
|
||||
{
|
||||
let Some(polkit) = polkit else {
|
||||
tracing::error!("polkit authority is unavailable; denying request");
|
||||
return Err(VarlinkWalldClientError::NotAuthorized);
|
||||
};
|
||||
|
||||
match check(polkit).await {
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => Err(VarlinkWalldClientError::NotAuthorized),
|
||||
Err(err) => {
|
||||
tracing::error!("polkit authorization check failed: {err:#}");
|
||||
Err(VarlinkWalldClientError::NotAuthorized)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn handle_wall_request(
|
||||
_source_pid: u32,
|
||||
polkit: Option<&PolkitAuthority>,
|
||||
source_pid: u32,
|
||||
source_uid: u32,
|
||||
source_tty: Option<String>,
|
||||
message: String,
|
||||
@@ -182,7 +239,10 @@ pub async fn handle_wall_request(
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: authorize against polkit
|
||||
authorize(polkit, |authority| {
|
||||
check_wall(authority, source_pid, group.as_deref())
|
||||
})
|
||||
.await?;
|
||||
|
||||
let body = tty_utils::format_wall_message(
|
||||
&username_for_uid(source_uid),
|
||||
@@ -216,14 +276,18 @@ pub async fn handle_wall_request(
|
||||
const DEFAULT_WRITE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
pub async fn handle_write_request(
|
||||
_source_pid: u32,
|
||||
polkit: Option<&PolkitAuthority>,
|
||||
source_pid: u32,
|
||||
source_uid: u32,
|
||||
source_tty: Option<String>,
|
||||
user: String,
|
||||
tty: Option<String>,
|
||||
message: String,
|
||||
) -> Result<VarlinkWriteResponse, VarlinkWalldClientError> {
|
||||
// TODO: authorize against polkit
|
||||
authorize(polkit, |authority| {
|
||||
check_write(authority, source_pid, &user, tty.as_deref())
|
||||
})
|
||||
.await?;
|
||||
|
||||
let sessions = tty_utils::sessions_for_user(&user);
|
||||
if sessions.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user