| 1 |
/* Alloy: the settings a laptop owner changes about their own machine. |
| 2 |
* |
| 3 |
* `alloy settings` fronts timedatectl, hostnamectl and localectl. Every one of |
| 4 |
* those actions ships as auth_admin_keep, so without this file the System tab |
| 5 |
* would raise a password prompt to change a timezone. Granting them outright to |
| 6 |
* an active local session in wheel is the honest reading: the person sitting at |
| 7 |
* the machine, already logged into it, setting its clock is not performing an |
| 8 |
* administrative act that a password would clarify. See wiki note |
| 9 |
* `alloy-privilege` for the ladder this is the first rung of, and for what is |
| 10 |
* deliberately left prompting. |
| 11 |
* |
| 12 |
* `active && local` is doing real work in the rule below: an ssh login is |
| 13 |
* neither, so these five rows prompt over ssh exactly as they would without |
| 14 |
* this file. That is not a gap. It is the same rule read honestly — nobody is |
| 15 |
* sitting at the machine — and the console answers it at the second rung, by |
| 16 |
* running the setter again under `pkttyagent`. Widening the grant to cover |
| 17 |
* remote sessions would trade the whole justification for one less prompt. |
| 18 |
* |
| 19 |
* The list is short on purpose. A rules file is a security artifact and should |
| 20 |
* be readable in one sitting; the failure mode to avoid is a grant that quietly |
| 21 |
* covers more than anyone remembers asking for. Omarchy issue 5708 is the |
| 22 |
* cautionary case, a first-run sudoers line of NOPASSWD on all of |
| 23 |
* /usr/bin/systemctl written to enable one unit. |
| 24 |
* |
| 25 |
* Not granted, deliberately: |
| 26 |
* |
| 27 |
* timedate1.set-time the clock row is display-only; the console does |
| 28 |
* not set the time by hand, and moving a system |
| 29 |
* clock invalidates certificates and reorders logs |
| 30 |
* timedate1.set-local-rtc nothing in Alloy offers it |
| 31 |
* hostname1.set-machine-info pretty hostname, icon, chassis, deployment and |
| 32 |
* location. Location in particular is not a thing |
| 33 |
* to hand over for a screen that sets a hostname |
| 34 |
* hostname1.get-product-uuid, .get-hardware-serial identifiers, not settings |
| 35 |
* NetworkManager.settings.modify.system nothing to grant: it already reads |
| 36 |
* allow_active=yes on this image, so saving a |
| 37 |
* system connection is answered without asking |
| 38 |
* rpmostree1.* changing the system image should be asked about; |
| 39 |
* the prompt there is the point |
| 40 |
* |
| 41 |
* CALLER CONSTRAINT. `hostnamectl hostname NAME` with no scope flag sets the |
| 42 |
* static, transient and pretty names, and the pretty one needs |
| 43 |
* set-machine-info, which is not granted here. The console must call |
| 44 |
* `hostnamectl --static hostname NAME`; hostnamed applies the static name to |
| 45 |
* the running kernel hostname on its own. Granting set-machine-info to avoid |
| 46 |
* one flag would trade a wider grant for less typing. |
| 47 |
* |
| 48 |
* Ordering: polkit reads /etc/polkit-1/rules.d and /usr/share/polkit-1/rules.d |
| 49 |
* as one lexically sorted set, and the first rule to return a value wins. This |
| 50 |
* file ships at 50- so anything a user drops in /etc with a lower number |
| 51 |
* overrides it outright. |
| 52 |
*/ |
| 53 |
|
| 54 |
polkit.addRule(function (action, subject) { |
| 55 |
var granted = [ |
| 56 |
"org.freedesktop.timedate1.set-timezone", |
| 57 |
"org.freedesktop.timedate1.set-ntp", |
| 58 |
"org.freedesktop.hostname1.set-static-hostname", |
| 59 |
"org.freedesktop.locale1.set-locale", |
| 60 |
"org.freedesktop.locale1.set-keyboard" |
| 61 |
]; |
| 62 |
|
| 63 |
/* active: the session in front of the screen, not one left open on another |
| 64 |
* VT. local: not over SSH, where "the person sitting at the machine" is the |
| 65 |
* whole justification and does not hold. wheel: the group Fedora's polkit |
| 66 |
* already treats as administrators, and the one `alloy install` puts the |
| 67 |
* first account in. |
| 68 |
* |
| 69 |
* Returning nothing rather than NOT for everything else, so this file |
| 70 |
* grants and never denies: a rule that returned NOT would override a later |
| 71 |
* one that had a better reason to allow something. |
| 72 |
*/ |
| 73 |
if (granted.indexOf(action.id) < 0) { |
| 74 |
return; |
| 75 |
} |
| 76 |
if (subject.active && subject.local && subject.isInGroup("wheel")) { |
| 77 |
return polkit.Result.YES; |
| 78 |
} |
| 79 |
}); |
| 80 |
|