18 files changed
558 "tracing",558 "tracing",
559]559]
560
561[[package]]
562name = "bindgen"
563version = "0.69.5"
564source = "registry+https://github.com/rust-lang/crates.io-index"
565checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
566dependencies = [
567 "bitflags 2.13.0",
568 "cexpr",
569 "clang-sys",
570 "itertools 0.12.1",
571 "lazy_static",
572 "lazycell",
573 "proc-macro2",
574 "quote",
575 "regex",
576 "rustc-hash 1.1.0",
577 "shlex 1.3.0",
578 "syn 2.0.118",
579]
580560
581[[package]]561[[package]]
582name = "bindgen"562name = "bindgen"
583version = "0.72.1"563version = "0.72.1"
584source = "registry+https://github.com/rust-lang/crates.io-index"564source = "registry+https://github.com/rust-lang/crates.io-index"
585checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"565checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
586dependencies = [566dependencies = [
587 "bitflags 2.13.0",567 "bitflags",
588 "cexpr",568 "cexpr",
589 "clang-sys",569 "clang-sys",
590 "itertools 0.13.0",570 "itertools 0.13.0",
598 "syn 2.0.118",578 "syn 2.0.118",
599]579]
600
601[[package]]
602name = "bitflags"
603version = "1.3.2"
604source = "registry+https://github.com/rust-lang/crates.io-index"
605checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
606580
607[[package]]581[[package]]
608name = "bitflags"582name = "bitflags"
1415checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"1389checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
1416dependencies = [1390dependencies = [
1417 "data-encoding",1391 "data-encoding",
1418 "syn 1.0.109",1392 "syn 2.0.118",
1419]1393]
14201394
1421[[package]]1395[[package]]
1566source = "registry+https://github.com/rust-lang/crates.io-index"1540source = "registry+https://github.com/rust-lang/crates.io-index"
1567checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"1541checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
1568dependencies = [1542dependencies = [
1569 "bitflags 2.13.0",1543 "bitflags",
1570 "block2",1544 "block2",
1571 "libc",1545 "libc",
1572 "objc2",1546 "objc2",
1706 "syn 2.0.118",1680 "syn 2.0.118",
1707]1681]
1708
1709[[package]]
1710name = "enum-repr"
1711version = "0.2.6"
1712source = "registry+https://github.com/rust-lang/crates.io-index"
1713checksum = "bad30c9c0fa1aaf1ae5010dab11f1117b15d35faf62cda4bbbc53b9987950f18"
1714dependencies = [
1715 "proc-macro2",
1716 "quote",
1717 "syn 1.0.109",
1718]
17191682
1720[[package]]1683[[package]]
1721name = "enum_dispatch"1684name = "enum_dispatch"
3123source = "registry+https://github.com/rust-lang/crates.io-index"3086source = "registry+https://github.com/rust-lang/crates.io-index"
3124checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"3087checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
3125
3126[[package]]
3127name = "itertools"
3128version = "0.12.1"
3129source = "registry+https://github.com/rust-lang/crates.io-index"
3130checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
3131dependencies = [
3132 "either",
3133]
31343088
3135[[package]]3089[[package]]
3136name = "itertools"3090name = "itertools"
3289 "spin 0.9.8",3243 "spin 0.9.8",
3290]3244]
3291
3292[[package]]
3293name = "lazycell"
3294version = "1.3.0"
3295source = "registry+https://github.com/rust-lang/crates.io-index"
3296checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
32973245
3298[[package]]3246[[package]]
3299name = "libc"3247name = "libc"
3323source = "registry+https://github.com/rust-lang/crates.io-index"3271source = "registry+https://github.com/rust-lang/crates.io-index"
3324checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"3272checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
3325dependencies = [3273dependencies = [
3326 "bitflags 2.13.0",3274 "bitflags",
3327 "libc",3275 "libc",
3328 "plain",3276 "plain",
3329 "redox_syscall 0.8.1",3277 "redox_syscall 0.8.1",
3611source = "registry+https://github.com/rust-lang/crates.io-index"3559source = "registry+https://github.com/rust-lang/crates.io-index"
3612checksum = "df9854ea6ad14e3f4698a7f03b65bce0833dd2d81d594a0e4a984170537146b6"3560checksum = "df9854ea6ad14e3f4698a7f03b65bce0833dd2d81d594a0e4a984170537146b6"
3613dependencies = [3561dependencies = [
3614 "bitflags 2.13.0",3562 "bitflags",
3615 "libc",3563 "libc",
3616 "log",3564 "log",
3617 "netlink-packet-core",3565 "netlink-packet-core",
3623source = "registry+https://github.com/rust-lang/crates.io-index"3571source = "registry+https://github.com/rust-lang/crates.io-index"
3624checksum = "e2288fcb784eb3defd5fb16f4c4160d5f477de192eac730f43e1d11c24d9a007"3572checksum = "e2288fcb784eb3defd5fb16f4c4160d5f477de192eac730f43e1d11c24d9a007"
3625dependencies = [3573dependencies = [
3626 "bitflags 2.13.0",3574 "bitflags",
3627 "libc",3575 "libc",
3628 "log",3576 "log",
3629 "netlink-packet-core",3577 "netlink-packet-core",
3699source = "registry+https://github.com/rust-lang/crates.io-index"3647source = "registry+https://github.com/rust-lang/crates.io-index"
3700checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"3648checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
3701dependencies = [3649dependencies = [
3702 "bitflags 2.13.0",3650 "bitflags",
3703 "cfg-if",3651 "cfg-if",
3704 "cfg_aliases",3652 "cfg_aliases",
3705 "libc",3653 "libc",
3710version = "0.1.9"3658version = "0.1.9"
3711dependencies = [3659dependencies = [
3712 "anyhow",3660 "anyhow",
3713 "bindgen 0.72.1",3661 "bindgen",
3714 "camino",3662 "camino",
3715 "cxx",3663 "cxx",
3716 "cxx-build",3664 "cxx-build",
3943source = "registry+https://github.com/rust-lang/crates.io-index"3891source = "registry+https://github.com/rust-lang/crates.io-index"
3944checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"3892checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
3945dependencies = [3893dependencies = [
3946 "bitflags 2.13.0",3894 "bitflags",
3947 "block2",3895 "block2",
3948 "dispatch2",3896 "dispatch2",
3949 "libc",3897 "libc",
3956source = "registry+https://github.com/rust-lang/crates.io-index"3904source = "registry+https://github.com/rust-lang/crates.io-index"
3957checksum = "c71e34919aba0d701380d911702455038a8a3587467fe0141d6a71501e7ffe48"3905checksum = "c71e34919aba0d701380d911702455038a8a3587467fe0141d6a71501e7ffe48"
3958dependencies = [3906dependencies = [
3959 "bitflags 2.13.0",3907 "bitflags",
3960 "objc2",3908 "objc2",
3961 "objc2-core-foundation",3909 "objc2-core-foundation",
3962 "objc2-foundation",3910 "objc2-foundation",
3976source = "registry+https://github.com/rust-lang/crates.io-index"3924source = "registry+https://github.com/rust-lang/crates.io-index"
3977checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"3925checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
3978dependencies = [3926dependencies = [
3979 "bitflags 2.13.0",3927 "bitflags",
3980 "block2",3928 "block2",
3981 "libc",3929 "libc",
3982 "objc2",3930 "objc2",
3989source = "registry+https://github.com/rust-lang/crates.io-index"3937source = "registry+https://github.com/rust-lang/crates.io-index"
3990checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a"3938checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a"
3991dependencies = [3939dependencies = [
3992 "bitflags 2.13.0",3940 "bitflags",
3993 "objc2",3941 "objc2",
3994 "objc2-core-foundation",3942 "objc2-core-foundation",
3995]3943]
4010source = "registry+https://github.com/rust-lang/crates.io-index"3958source = "registry+https://github.com/rust-lang/crates.io-index"
4011checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396"3959checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396"
4012dependencies = [3960dependencies = [
4013 "bitflags 2.13.0",3961 "bitflags",
4014 "dispatch2",3962 "dispatch2",
4015 "libc",3963 "libc",
4016 "objc2",3964 "objc2",
4217 "windows-strings",4165 "windows-strings",
4218]4166]
4219
4220[[package]]
4221name = "pam-client"
4222version = "0.5.0"
4223source = "registry+https://github.com/rust-lang/crates.io-index"
4224checksum = "51bd776116a7ada5ebbe31f54cdc5b1030ed7265686cf7c8a21c057a2f8dab9a"
4225dependencies = [
4226 "bitflags 1.3.2",
4227 "enum-repr",
4228 "libc",
4229 "pam-sys",
4230 "rpassword",
4231 "rustversion",
4232]
4233
4234[[package]]
4235name = "pam-sys"
4236version = "1.0.0-alpha5"
4237source = "registry+https://github.com/rust-lang/crates.io-index"
4238checksum = "ce9484729b3e52c0bacdc5191cb6a6a5f31ef4c09c5e4ab1209d3340ad9e997b"
4239dependencies = [
4240 "bindgen 0.69.5",
4241 "libc",
4242]
42434167
4244[[package]]4168[[package]]
4245name = "papaya"4169name = "papaya"
4509 "time",4433 "time",
4510]4434]
4511
4512[[package]]
4513name = "polkit-backend"
4514version = "0.1.9"
4515dependencies = [
4516 "anyhow",
4517 "clap",
4518 "nix",
4519 "pam-client",
4520 "remowt-polkit-shared",
4521 "remowt-ui-prompt",
4522 "tokio",
4523 "tracing",
4524 "tracing-subscriber",
4525 "zbus",
4526 "zbus_polkit",
4527]
45284435
4529[[package]]4436[[package]]
4530name = "polling"4437name = "polling"
4761source = "registry+https://github.com/rust-lang/crates.io-index"4668source = "registry+https://github.com/rust-lang/crates.io-index"
4762checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"4669checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
4763dependencies = [4670dependencies = [
4764 "bitflags 2.13.0",4671 "bitflags",
4765 "num-traits",4672 "num-traits",
4766 "rand 0.9.4",4673 "rand 0.9.4",
4767 "rand_chacha 0.9.0",4674 "rand_chacha 0.9.0",
4988source = "registry+https://github.com/rust-lang/crates.io-index"4895source = "registry+https://github.com/rust-lang/crates.io-index"
4989checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"4896checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
4990dependencies = [4897dependencies = [
4991 "bitflags 2.13.0",4898 "bitflags",
4992]4899]
49934900
4994[[package]]4901[[package]]
4997source = "registry+https://github.com/rust-lang/crates.io-index"4904source = "registry+https://github.com/rust-lang/crates.io-index"
4998checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7"4905checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7"
4999dependencies = [4906dependencies = [
5000 "bitflags 2.13.0",4907 "bitflags",
5001]4908]
50024909
5003[[package]]4910[[package]]
5262 "windows-sys 0.52.0",5169 "windows-sys 0.52.0",
5263]5170]
5264
5265[[package]]
5266name = "rpassword"
5267version = "6.0.1"
5268source = "registry+https://github.com/rust-lang/crates.io-index"
5269checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956"
5270dependencies = [
5271 "libc",
5272 "serde",
5273 "serde_json",
5274 "winapi",
5275]
52765171
5277[[package]]5172[[package]]
5278name = "rsa"5173name = "rsa"
5320checksum = "bbf893f64684e58da8a68d56a5e84d1cf0440226274c515770fe267707a7d0b0"5215checksum = "bbf893f64684e58da8a68d56a5e84d1cf0440226274c515770fe267707a7d0b0"
5321dependencies = [5216dependencies = [
5322 "aes 0.9.1",5217 "aes 0.9.1",
5323 "bitflags 2.13.0",5218 "bitflags",
5324 "block-padding 0.4.2",5219 "block-padding 0.4.2",
5325 "byteorder",5220 "byteorder",
5326 "bytes",5221 "bytes",
5484source = "registry+https://github.com/rust-lang/crates.io-index"5379source = "registry+https://github.com/rust-lang/crates.io-index"
5485checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"5380checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
5486dependencies = [5381dependencies = [
5487 "bitflags 2.13.0",5382 "bitflags",
5488 "errno",5383 "errno",
5489 "libc",5384 "libc",
5490 "linux-raw-sys 0.4.15",5385 "linux-raw-sys 0.4.15",
5497source = "registry+https://github.com/rust-lang/crates.io-index"5392source = "registry+https://github.com/rust-lang/crates.io-index"
5498checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"5393checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
5499dependencies = [5394dependencies = [
5500 "bitflags 2.13.0",5395 "bitflags",
5501 "errno",5396 "errno",
5502 "libc",5397 "libc",
5503 "linux-raw-sys 0.12.1",5398 "linux-raw-sys 0.12.1",
5700source = "registry+https://github.com/rust-lang/crates.io-index"5595source = "registry+https://github.com/rust-lang/crates.io-index"
5701checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"5596checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
5702dependencies = [5597dependencies = [
5703 "bitflags 2.13.0",5598 "bitflags",
5704 "core-foundation 0.10.1",5599 "core-foundation 0.10.1",
5705 "core-foundation-sys",5600 "core-foundation-sys",
5706 "libc",5601 "libc",
5956source = "registry+https://github.com/rust-lang/crates.io-index"5851source = "registry+https://github.com/rust-lang/crates.io-index"
5957checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4"5852checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4"
5958dependencies = [5853dependencies = [
5959 "bitflags 2.13.0",5854 "bitflags",
5960]5855]
59615856
5962[[package]]5857[[package]]
6184source = "registry+https://github.com/rust-lang/crates.io-index"6079source = "registry+https://github.com/rust-lang/crates.io-index"
6185checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"6080checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
6186dependencies = [6081dependencies = [
6187 "bitflags 2.13.0",6082 "bitflags",
6188 "core-foundation 0.9.4",6083 "core-foundation 0.9.4",
6189 "system-configuration-sys",6084 "system-configuration-sys",
6190]6085]
6610source = "registry+https://github.com/rust-lang/crates.io-index"6505source = "registry+https://github.com/rust-lang/crates.io-index"
6611checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"6506checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
6612dependencies = [6507dependencies = [
6613 "bitflags 2.13.0",6508 "bitflags",
6614 "bytes",6509 "bytes",
6615 "futures-util",6510 "futures-util",
6616 "http",6511 "http",
6953checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"6848checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
6954dependencies = [6849dependencies = [
6955 "arrayvec",6850 "arrayvec",
6956 "bitflags 2.13.0",6851 "bitflags",
6957 "cursor-icon",6852 "cursor-icon",
6958 "log",6853 "log",
6959 "memchr",6854 "memchr",
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -89,7 +89,6 @@
zbus = "5.16.0"
zbus_polkit = "5.0.0"
tokio-util = "0.7.11"
-pam-client = "0.5.0"
[profile.dev]
panic = "abort"
--- a/remowt/cmds/polkit-dbus-helper/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-name = "polkit-backend"
-description = "polkit/PAM D-Bus authentication backend for remowt"
-version.workspace = true
-edition = "2021"
-license.workspace = true
-
-[dependencies]
-anyhow.workspace = true
-clap = { workspace = true, features = ["derive"] }
-nix.workspace = true
-pam-client.workspace = true
-remowt-polkit-shared.workspace = true
-tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread"] }
-tracing.workspace = true
-tracing-subscriber.workspace = true
-remowt-ui-prompt.workspace = true
-zbus = { workspace = true, features = ["tokio"] }
-zbus_polkit = { workspace = true, features = ["tokio"] }
--- a/remowt/cmds/polkit-dbus-helper/README.adoc
+++ /dev/null
@@ -1,8 +0,0 @@
-== What is it?
-
-Usually, there is a `polkit-agent-helper-1` suid binary installed on the system with polkit package.
-
-This, however, an alternative to that approach, a system daemon listening for dbus requests, which works
-without using suid binaries.
-
-In future it will provide some additional features.
--- a/remowt/cmds/polkit-dbus-helper/etc/systemd/system/remowt-polkit-helper.service
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=Remowt polkit helper service
-
-[Service]
-Type=dbus
-BusName=lach.polkit.helper1
-ExecStart=@libexecdir@/polkit-backend
-# TODO: Hardening
-
-[Install]
-WantedBy=multi-user.target
-Alias=dbus-lach.polkit.helper1.service
--- a/remowt/cmds/polkit-dbus-helper/share/dbus-1/system-services/lach.polkit.helper1.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-[D-BUS Service]
-Name=lach.polkit.helper1
-Exec=/bin/false
-User=root
-SystemdService=dbus-lach.polkit.helper1.service
--- a/remowt/cmds/polkit-dbus-helper/share/dbus-1/system.d/lach.polkit.helper1.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "https://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
- <policy user="root">
- <allow own = "lach.polkit.helper1"/>
- <allow send_interface="lach.PolkitInputHandler"/>
- </policy>
- <policy context="default">
- <allow send_destination="lach.polkit.helper1"/>
- <deny send_interface="lach.PolkitInputHandler"/>
- </policy>
-</busconfig>
--- a/remowt/cmds/polkit-dbus-helper/src/main.rs
+++ /dev/null
@@ -1,236 +0,0 @@
-use std::collections::{HashMap, HashSet};
-use std::ffi::{CStr, CString};
-use std::future::pending;
-use std::sync::LazyLock;
-
-use anyhow::Context as _;
-use clap::Parser;
-use nix::unistd::{setuid, Uid, User};
-use pam_client::{Context, ConversationHandler, ErrorCode, Flag};
-use remowt_polkit_shared::BackendRequest;
-use remowt_ui_prompt::dbus::DbusPrompterProxyBlocking;
-use remowt_ui_prompt::BlockingPrompter;
-use tokio::task::{block_in_place, spawn_blocking};
-use tracing::trace;
-use zbus::fdo;
-use zbus::message::Header;
-use zbus::zvariant::OwnedValue;
-use zbus::{blocking, interface, proxy, Connection};
-
-struct Helper {
- connection: Connection,
- blocking_connection: blocking::Connection,
-}
-
-static ALLOWED_ENVIRONMENT: LazyLock<HashSet<&str>> = LazyLock::new(|| {
- [
- // pam ssh agent auth
- "SSH_AUTH_SOCK",
- // ssh itself provides this when running PAM
- "SSH_AUTH_INFO_0",
- // contains user which ran sudo
- "SUDO_USER",
- ]
- .into_iter()
- .collect()
-});
-
-struct Conversation<P>(P);
-impl<P: BlockingPrompter> Conversation<P> {
- fn prompt_inner(&self, echo: bool, prompt: &CStr) -> Result<CString, ErrorCode> {
- trace!("do prompt");
- let out = self
- .0
- .prompt_text(echo, &prompt.to_string_lossy(), "PAM prompt request", &[])
- .map_err(|e| {
- trace!("prompt error: {e}");
- ErrorCode::CONV_ERR
- })?;
- CString::new(out).map_err(|_| ErrorCode::CONV_AGAIN)
- }
- fn text_inner(&self, error: bool, msg: &CStr) {
- trace!("do text");
- let msg = msg.to_string_lossy();
- let _ = self.0.display_text(error, &msg, &[]);
- }
-}
-impl<P: BlockingPrompter> ConversationHandler for Conversation<P> {
- fn prompt_echo_on(&mut self, prompt: &CStr) -> Result<CString, ErrorCode> {
- self.prompt_inner(true, prompt)
- }
-
- fn prompt_echo_off(&mut self, prompt: &CStr) -> Result<CString, ErrorCode> {
- self.prompt_inner(false, prompt)
- }
-
- fn text_info(&mut self, msg: &CStr) {
- self.text_inner(false, msg)
- }
-
- fn error_msg(&mut self, msg: &CStr) {
- self.text_inner(true, msg)
- }
-
- fn radio_prompt(&mut self, prompt: &CStr) -> Result<bool, ErrorCode> {
- let prompt = prompt.to_string_lossy();
- let result = self
- .0
- .prompt_radio(&prompt, "PAM prompt request", &[])
- .map_err(|_| ErrorCode::CONV_ERR)?;
- Ok(result)
- }
-}
-
-#[proxy(
- default_service = "org.freedesktop.DBus",
- default_path = "/org/freedesktop/DBus"
-)]
-trait DBus {
- fn get_connection_credentials(&self, body: &str) -> zbus::Result<HashMap<String, OwnedValue>>;
-}
-
-#[interface(name = "lach.PolkitHelper")]
-impl Helper {
- async fn init_conversation(
- &self,
- request: BackendRequest,
- #[zbus(header)] hdr: Header<'_>,
- ) -> fdo::Result<()> {
- let Some(sender) = hdr.sender().map(|v| v.to_owned()) else {
- trace!("missing sender");
- return Err(fdo::Error::AuthFailed("missing sender".to_owned()));
- };
-
- let dbus = DBusProxy::new(&self.connection).await?;
-
- // TOCTOU: sender might be already disconnected, and there might be another
- // user with different user id here, but does it matters?
- let reply = dbus.get_connection_credentials(&sender).await?;
- let connection_uid: u32 = (&reply["UnixUserID"]).try_into().unwrap();
-
- let identity = request.identity.clone();
- let blocking_connection = self.blocking_connection.clone();
- let thread_result: fdo::Result<()> = block_in_place(move || {
- trace!("find user");
- let Some(identity_uid) = identity.uid() else {
- return Err(fdo::Error::AuthFailed("can't process identity".to_owned()));
- };
- let user = User::from_uid(identity_uid)
- .map_err(|_| fdo::Error::AuthFailed("error querying user".to_owned()))?
- .ok_or_else(|| fdo::Error::AuthFailed("uid not found".to_owned()))?;
-
- let responder = DbusPrompterProxyBlocking::new(
- &blocking_connection,
- sender,
- request.prompter_path,
- )?;
- let conversation = Conversation(responder);
- trace!("run context for {}", &user.name);
- let mut ctx = Context::new(
- // TODO: Should another scope be used?
- "login",
- Some(&user.name),
- conversation,
- )
- .map_err(|_| fdo::Error::Failed("pam context init failed".to_owned()))?;
-
- trace!("fill env");
- for (k, v) in request.environment {
- if k.contains('=') || !ALLOWED_ENVIRONMENT.contains(k.as_str()) {
- continue;
- }
- let _ = ctx.putenv(format!("{k}={v}"));
- }
-
- trace!("authenticate");
- ctx.authenticate(Flag::NONE)
- .map_err(|_| fdo::Error::AuthFailed("pam authentication failed".to_owned()))?;
-
- trace!("acct mgmt");
- ctx.acct_mgmt(Flag::NONE)
- .map_err(|_| fdo::Error::AuthFailed("pam acct mgmt failed".to_owned()))?;
-
- Ok(())
- });
-
- thread_result?;
-
- trace!("respond");
- let proxy = zbus_polkit::policykit1::AuthorityProxy::new(&self.connection).await?;
-
- let identity_details = request
- .identity
- .details
- .iter()
- .map(|(k, v)| (k.as_str(), (**v).try_clone().expect("success")))
- .collect::<HashMap<_, _>>();
- proxy
- .authentication_agent_response2(
- connection_uid,
- &request.cookie,
- &zbus_polkit::policykit1::Identity {
- identity_kind: &request.identity.kind,
- identity_details: &identity_details,
- },
- )
- .await?;
- Ok(())
- }
-}
-
-const OBJ_PATH: &str = "/lach/PolkitHelper";
-
-#[derive(Parser)]
-struct Opts {
- /// Not recommended: start as a session connection, then use escalation
- /// to respond to polkit requests.
- #[arg(long)]
- session: bool,
-}
-
-#[tokio::main]
-async fn main() -> anyhow::Result<()> {
- tracing_subscriber::fmt::init();
- let opts = Opts::parse();
- let connection = if opts.session {
- Connection::session().await
- } else {
- Connection::system().await
- }
- .context("failed to open connection")?;
-
- let session = opts.session;
- let blocking_connection: anyhow::Result<blocking::Connection> = spawn_blocking(move || {
- Ok(if session {
- blocking::Connection::session()?
- } else {
- blocking::Connection::system()?
- })
- })
- .await?;
- let blocking_connection = blocking_connection.context("failed to open blocking connection")?;
-
- if opts.session {
- setuid(Uid::from_raw(0))
- .context("polkit-backend needs to be suid if run in session mode")?;
- }
-
- connection
- .object_server()
- .at(
- OBJ_PATH,
- Helper {
- connection: connection.clone(),
- blocking_connection,
- },
- )
- .await
- .context("failed listen path")?;
-
- connection
- .request_name("lach.polkit.helper1")
- .await
- .context("failed to request name")?;
-
- pending().await
-}
--- a/remowt/cmds/remowt-agent/src/helper/dbus.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use std::collections::HashMap;
-use std::marker::PhantomData;
-
-use remowt_polkit_shared::{BackendRequest, Identity};
-use remowt_ui_prompt::dbus::DbusPrompterInterface;
-use remowt_ui_prompt::Prompter;
-use zbus::Connection;
-
-use crate::PolkitHelperProxy;
-
-use super::Helper;
-
-struct TemporaryPrompterInterface<P: Prompter + 'static> {
- connection: Connection,
- path: String,
- _marker: PhantomData<P>,
-}
-impl<P: Prompter + 'static> TemporaryPrompterInterface<P> {
- async fn new(connection: Connection, prompter: P) -> Self {
- let path = format!(
- "/remowt/prompters/{}",
- uuid::Uuid::new_v4().to_string().replace("-", "_")
- );
- let _ = connection
- .object_server()
- .at(path.clone(), DbusPrompterInterface(prompter))
- .await;
- Self {
- connection,
- path,
- _marker: PhantomData,
- }
- }
-}
-impl<P: Prompter + Send + Sync + 'static> Drop for TemporaryPrompterInterface<P> {
- fn drop(&mut self) {
- // Removal is async because of async RwLock used inside...
- // We should not care about its reuse
- let connection = self.connection.clone();
- let path = std::mem::take(&mut self.path);
- tokio::spawn(async move {
- let _ = connection
- .object_server()
- .remove::<DbusPrompterInterface<P>, String>(path)
- .await;
- });
- }
-}
-
-#[derive(Clone)]
-pub struct DbusHelper {
- connection: Connection,
- helper: PolkitHelperProxy<'static>,
-}
-impl DbusHelper {
- pub async fn new(connection: Connection) -> zbus::Result<Self> {
- let helper = PolkitHelperProxy::new(&connection).await?;
- Ok(Self { connection, helper })
- }
-}
-impl Helper for DbusHelper {
- async fn help_me<P: Prompter + Send + Sync + 'static>(
- &self,
- cookie: &str,
- prompter: P,
- identity: Identity,
- ) -> anyhow::Result<()> {
- let prompter = TemporaryPrompterInterface::new(self.connection.clone(), prompter).await;
- self.helper
- .init_conversation(
- BackendRequest {
- cookie: cookie.to_owned(),
- environment: HashMap::new(),
- prompter_path: prompter.path.clone(),
- identity,
- }, // cookie.to_owned(), HashMap::new(), prompter.path.clone()
- )
- .await?;
- Ok(())
- }
-}
--- a/remowt/cmds/remowt-agent/src/helper/mod.rs
+++ b/remowt/cmds/remowt-agent/src/helper/mod.rs
@@ -2,12 +2,10 @@
use remowt_polkit_shared::Identity;
use remowt_ui_prompt::Prompter;
-mod dbus;
mod protocol;
mod socket;
mod suid;
-pub use dbus::DbusHelper;
pub use socket::SocketHelper;
pub use suid::SuidHelper;
--- a/remowt/cmds/remowt-agent/src/main.rs
+++ b/remowt/cmds/remowt-agent/src/main.rs
@@ -18,7 +18,7 @@
};
use remowt_link_shared::iroh_tunnel::TunnelDialer;
use remowt_link_shared::{editor::EditorEndpointsClient, Address, BifConfig};
-use remowt_polkit_shared::{emphasize, BackendRequest, Identity, PidDisplay};
+use remowt_polkit_shared::{emphasize, Identity, PidDisplay};
use remowt_ui_prompt::bifrost::PromptEndpointsClient;
use remowt_ui_prompt::rofi::RofiPrompter;
use remowt_ui_prompt::{PrependSourcePrompter, Prompter, Source};
@@ -29,7 +29,7 @@
use tracing::{debug, trace};
use zbus::fdo;
use zbus::zvariant::{OwnedValue, Str};
-use zbus::{interface, proxy, Connection};
+use zbus::{interface, Connection};
use zbus_polkit::policykit1::Subject;
use self::helper::{Helper, SocketHelper, SuidHelper};
@@ -199,15 +199,6 @@
}
const OBJ_PATH: &str = "/org/freedesktop/PolicyKit1/AuthenticationAgent";
-
-#[proxy(
- interface = "lach.PolkitHelper",
- default_service = "lach.polkit.helper1",
- default_path = "/lach/PolkitHelper"
-)]
-trait PolkitHelper {
- fn init_conversation(&self, request: BackendRequest) -> zbus::Result<()>;
-}
#[derive(Parser)]
enum Opts {
--- a/remowt/crates/polkit-shared/src/lib.rs
+++ b/remowt/crates/polkit-shared/src/lib.rs
@@ -103,11 +103,3 @@
}
}
}
-
-#[derive(Serialize, Deserialize, Type, PartialEq, Debug)]
-pub struct BackendRequest {
- pub cookie: String,
- pub environment: HashMap<String, String>,
- pub prompter_path: String,
- pub identity: Identity,
-}
--- a/remowt/crates/remowt-link-shared/Cargo.toml
+++ b/remowt/crates/remowt-link-shared/Cargo.toml
@@ -9,7 +9,7 @@
anyhow.workspace = true
bifrostlink.workspace = true
bytes.workspace = true
-camino = { workspace = true }
+camino = { workspace = true, features = ["serde1"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror.workspace = true
--- /dev/null
+++ b/remowt/crates/remowt-link-shared/src/gateway.rs
@@ -0,0 +1,100 @@
+use std::path::{Path, PathBuf};
+
+use anyhow::{anyhow, Context as _};
+use bifrostlink::{Rpc, Rtt};
+use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
+use tokio::net::{UnixListener, UnixStream};
+use tracing::{debug, warn};
+use uuid::Uuid;
+
+use crate::port::child_port;
+use crate::{Address, BifConfig};
+
+pub const SOCKET_ENV: &str = "REMOWT_AGENT_SOCKET";
+
+pub const SOCKET_NAME: &str = "agent.sock";
+
+pub fn local_socket() -> anyhow::Result<PathBuf> {
+ let dir = std::env::var_os("XDG_RUNTIME_DIR").context("XDG_RUNTIME_DIR not set")?;
+ Ok(PathBuf::from(dir).join("remowt-local"))
+}
+
+pub fn socket_path() -> anyhow::Result<PathBuf> {
+ match std::env::var_os(SOCKET_ENV) {
+ Some(p) => Ok(PathBuf::from(p)),
+ None => local_socket(),
+ }
+}
+
+fn peer_tag(addr: &Address) -> u8 {
+ match addr {
+ Address::User => 0,
+ Address::Agent => 1,
+ Address::AgentPrivileged => 2,
+ _ => unreachable!(),
+ }
+}
+fn untag_peer(tag: u8) -> anyhow::Result<Address> {
+ Ok(match tag {
+ 0 => Address::User,
+ 1 => Address::Agent,
+ 2 => Address::AgentPrivileged,
+ _ => unreachable!(),
+ })
+}
+
+pub async fn serve(rpc: Rpc<BifConfig>, path: &Path) -> anyhow::Result<()> {
+ let _ = tokio::fs::remove_file(path).await;
+ let listener = UnixListener::bind(path)
+ .with_context(|| format!("binding agent gateway at {}", path.display()))?;
+ let tag = peer_tag(&rpc.me());
+ tokio::spawn(async move {
+ loop {
+ let mut stream = match listener.accept().await {
+ Ok((stream, _)) => stream,
+ Err(e) => {
+ warn!("gateway accept failed: {e}");
+ continue;
+ }
+ };
+ let id = Uuid::new_v4().as_u128();
+ let mut hello = [0u8; 17];
+ hello[0] = tag;
+ hello[1..].copy_from_slice(&id.to_be_bytes());
+ if let Err(e) = stream.write_all(&hello).await {
+ warn!("gateway handshake failed: {e}");
+ continue;
+ }
+ debug!("gateway client {id:032x}");
+ let (rx, tx) = stream.into_split();
+ rpc.add_direct(
+ Address::Ephemeral(Uuid::from_u128(id)),
+ child_port(rx, tx),
+ Rtt(0),
+ );
+ }
+ });
+ Ok(())
+}
+
+pub async fn connect(path: &Path) -> anyhow::Result<Rpc<BifConfig>> {
+ let mut stream = UnixStream::connect(path)
+ .await
+ .with_context(|| format!("connecting to agent gateway at {}", path.display()))?;
+
+ let mut hello = [0u8; 17];
+ stream
+ .read_exact(&mut hello)
+ .await
+ .context("reading gateway handshake")?;
+ let peer = untag_peer(hello[0])?;
+ let id = u128::from_be_bytes(hello[1..].try_into().expect("16 bytes"));
+
+ let (rx, tx) = stream.into_split();
+ let rpc = Rpc::<BifConfig>::new(Address::Ephemeral(Uuid::from_u128(id)));
+ rpc.add_direct(peer, child_port(rx, tx), Rtt(0));
+ rpc.wait_for_connection_to(Address::User)
+ .await
+ .map_err(|_| anyhow!("no route to the User through the agent"))?;
+ Ok(rpc)
+}
--- a/remowt/crates/remowt-ui-prompt/Cargo.toml
+++ b/remowt/crates/remowt-ui-prompt/Cargo.toml
@@ -2,19 +2,15 @@
name = "remowt-ui-prompt"
description = "Interactive UI prompt endpoint for remowt (D-Bus)"
version.workspace = true
-edition = "2021"
+edition.workspace = true
license.workspace = true
[dependencies]
anyhow.workspace = true
bifrostlink.workspace = true
bifrostlink-macros.workspace = true
+remowt-link-shared.workspace = true
serde.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = ["io-util", "macros", "process", "rt"] }
tracing.workspace = true
-zbus = { workspace = true, optional = true }
-
-[features]
-default = ["dbus"]
-dbus = ["dep:zbus"]
--- a/remowt/crates/remowt-ui-prompt/src/auto.rs
+++ b/remowt/crates/remowt-ui-prompt/src/auto.rs
@@ -1,45 +1,41 @@
-use anyhow::bail;
+use std::path::Path;
+
+use bifrostlink::declarative::RemoteEndpoints as _;
+use remowt_link_shared::{Address, BifConfig, gateway};
use tracing::debug;
-use zbus::fdo::DBusProxy;
-use zbus::names::BusName;
-use crate::dbus::{DbusPrompterProxy, BUS_NAME, PROMPTER_PATH};
+use crate::bifrost::PromptEndpointsClient;
use crate::rofi::RofiPrompter;
use crate::{Prompter, Result, Source};
pub struct AutoPrompter {
- dbus: Option<DbusPrompterProxy<'static>>,
+ remote: Option<PromptEndpointsClient<BifConfig>>,
fallback: RofiPrompter,
}
impl AutoPrompter {
pub async fn new() -> Self {
- let dbus = match Self::try_dbus().await {
- Ok(p) => Some(p),
+ let remote = match gateway::local_socket() {
+ Ok(path) => Self::try_connect(&path).await,
Err(e) => {
- debug!("dbus prompter unavailable, falling back to rofi: {e}");
+ debug!("no local gateway socket, falling back to rofi: {e}");
None
}
};
Self {
- dbus,
+ remote,
fallback: RofiPrompter,
}
}
- async fn try_dbus() -> anyhow::Result<DbusPrompterProxy<'static>> {
- let conn = zbus::Connection::session().await?;
- let dbus = DBusProxy::new(&conn).await?;
- let name = BusName::try_from(BUS_NAME)?;
- if !dbus.name_has_owner(name).await? {
- bail!("{BUS_NAME} not registered on session bus");
+ async fn try_connect(path: &Path) -> Option<PromptEndpointsClient<BifConfig>> {
+ match gateway::connect(path).await {
+ Ok(rpc) => Some(PromptEndpointsClient::wrap(rpc.remote(Address::User))),
+ Err(e) => {
+ debug!("local prompt agent unavailable, falling back to rofi: {e}");
+ None
+ }
}
- let proxy = DbusPrompterProxy::builder(&conn)
- .destination(BUS_NAME)?
- .path(PROMPTER_PATH)?
- .build()
- .await?;
- Ok(proxy)
}
}
@@ -51,8 +47,8 @@
variants: &[&str],
source: &[Source],
) -> Result<u32> {
- if let Some(dbus) = &self.dbus {
- return Prompter::prompt_enum(dbus, prompt, description, variants, source).await;
+ if let Some(remote) = &self.remote {
+ return Prompter::prompt_enum(remote, prompt, description, variants, source).await;
}
self.fallback
.prompt_enum(prompt, description, variants, source)
@@ -66,8 +62,8 @@
description: &str,
source: &[Source],
) -> Result<String> {
- if let Some(dbus) = &self.dbus {
- return Prompter::prompt_text(dbus, echo, prompt, description, source).await;
+ if let Some(remote) = &self.remote {
+ return Prompter::prompt_text(remote, echo, prompt, description, source).await;
}
self.fallback
.prompt_text(echo, prompt, description, source)
@@ -75,8 +71,8 @@
}
async fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {
- if let Some(dbus) = &self.dbus {
- return Prompter::display_text(dbus, error, description, source).await;
+ if let Some(remote) = &self.remote {
+ return Prompter::display_text(remote, error, description, source).await;
}
self.fallback.display_text(error, description, source).await
}
--- a/remowt/crates/remowt-ui-prompt/src/dbus.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-use zbus::interface;
-use zbus::{fdo, proxy};
-
-use crate::Source;
-use crate::{BlockingPrompter, Result};
-use crate::{Error, Prompter};
-
-pub const BUS_NAME: &str = "lach.RemowtAskpass";
-pub const PROMPTER_PATH: &str = "/lach/Askpass";
-
-pub struct DbusPrompterInterface<P>(pub P);
-
-#[interface(name = "lach.PolkitInputHandler")]
-impl<P: Prompter + Send + Sync + 'static> DbusPrompterInterface<P> {
- async fn prompt_enum(
- &self,
- prompt: &str,
- description: &str,
- variants: Vec<String>,
- source: Vec<Source>,
- ) -> fdo::Result<u32> {
- let variants: Vec<&str> = variants.iter().map(|v| v.as_str()).collect();
- Ok(self
- .0
- .prompt_enum(prompt, description, &variants, &source)
- .await?)
- }
- async fn prompt_text(
- &self,
- echo: bool,
- prompt: &str,
- description: &str,
- source: Vec<Source>,
- ) -> fdo::Result<String> {
- Ok(self
- .0
- .prompt_text(echo, prompt, description, &source)
- .await?)
- }
- async fn display_text(
- &self,
- error: bool,
- description: &str,
- source: Vec<Source>,
- ) -> fdo::Result<()> {
- Ok(self.0.display_text(error, description, &source).await?)
- }
-}
-
-#[proxy(interface = "lach.PolkitInputHandler")]
-pub trait DbusPrompter {
- async fn prompt_enum(
- &self,
- prompt: &str,
- description: &str,
- variants: &[&str],
- source: &[Source],
- ) -> fdo::Result<u32>;
- async fn prompt_text(
- &self,
- echo: bool,
- prompt: &str,
- description: &str,
- source: &[Source],
- ) -> fdo::Result<String>;
- async fn display_text(
- &self,
- error: bool,
- description: &str,
- source: &[Source],
- ) -> fdo::Result<()>;
-}
-
-impl Prompter for DbusPrompterProxy<'_> {
- async fn prompt_enum(
- &self,
- prompt: &str,
- description: &str,
- variants: &[&str],
- source: &[Source],
- ) -> Result<u32> {
- Ok(self
- .prompt_enum(prompt, description, variants, source)
- .await?)
- }
-
- async fn prompt_text(
- &self,
- echo: bool,
- prompt: &str,
- description: &str,
- source: &[Source],
- ) -> Result<String> {
- Ok(self.prompt_text(echo, prompt, description, source).await?)
- }
-
- async fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {
- Ok(self.display_text(error, description, source).await?)
- }
-}
-impl BlockingPrompter for DbusPrompterProxyBlocking<'_> {
- fn prompt_enum(
- &self,
- prompt: &str,
- description: &str,
- variants: &[&str],
- source: &[Source],
- ) -> Result<u32> {
- Ok(self.prompt_enum(prompt, description, variants, source)?)
- }
-
- fn prompt_text(
- &self,
- echo: bool,
- prompt: &str,
- description: &str,
- source: &[Source],
- ) -> Result<String> {
- Ok(self.prompt_text(echo, prompt, description, source)?)
- }
-
- fn display_text(&self, error: bool, description: &str, source: &[Source]) -> Result<()> {
- Ok(self.display_text(error, description, source)?)
- }
-}
-
-impl From<fdo::Error> for Error {
- fn from(value: fdo::Error) -> Self {
- if matches!(value, fdo::Error::NoReply(_)) {
- return Self::Cancel;
- }
- Self::InputError(format!("{value}"))
- }
-}
-impl From<Error> for fdo::Error {
- fn from(value: Error) -> Self {
- match value {
- Error::Cancel => fdo::Error::NoReply("input was cancelled".to_owned()),
- Error::Remote(e) => fdo::Error::NoReply(format!("remote error occured: {e}")),
- Error::InputError(e) => fdo::Error::Failed(e),
- }
- }
-}
--- a/remowt/crates/remowt-ui-prompt/src/lib.rs
+++ b/remowt/crates/remowt-ui-prompt/src/lib.rs
@@ -5,7 +5,6 @@
pub mod auto;
pub mod bifrost;
-pub mod dbus;
pub mod rofi;
#[derive(thiserror::Error, Debug, serde::Serialize, serde::Deserialize)]
@@ -20,7 +19,6 @@
pub type Result<T, E = Error> = result::Result<T, E>;
-#[cfg_attr(feature = "dbus", derive(zbus::zvariant::Type))]
#[derive(serde::Serialize, serde::Deserialize, Clone)]
pub struct Source(pub Cow<'static, str>);
impl fmt::Display for Source {