Skip to content

Commit b7decf6

Browse files
committed
Implement optional admin authorization via qrexec
See included README for details. Issue: QubesOS/qubes-issues#2695
1 parent 05f2ea1 commit b7decf6

29 files changed

+912
-55
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ all:
2424
ifeq ($(ENABLE_SELINUX),1)
2525
$(MAKE) -C selinux -f /usr/share/selinux/devel/Makefile -- $(selinux_policies)
2626
endif
27+
$(MAKE) -C passwordless-root
2728

2829
clean:
2930
make -C misc clean

archlinux/PKGBUILD.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ build() {
3838
# Fix for archlinux sbindir
3939
sed 's:/usr/sbin/ntpdate:/usr/bin/ntpdate:g' -i qubes-rpc/sync-ntp-clock
4040

41-
for dir in qubes-rpc misc; do
41+
for dir in qubes-rpc misc passwordless-root; do
4242
make -C "$dir" VERSION=${pkgver}
4343
done
4444
}

debian/qubes-core-agent-passwordless-root.displace-extension

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
etc/polkit-1/rules.d/00-qubes-allow-all.rules
1+
etc/qubes/admin-authzd.conf
22
etc/sudoers.d/qubes
3-
usr/share/pam-configs/su.qubes
3+
usr/share/pam-configs/qubes-admin-authz
4+
usr/bin/qubes-admin-authzd
5+
usr/lib/*/security/pam_qubes_admin_authz.so
6+
lib/systemd/system/qubes-admin-authzd.service
7+
usr/share/doc/qubes-core-agent-passwordless-root/README.md

debian/qubes-core-agent-passwordless-root.postinst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ pam-auth-update --package
2626

2727
#DEBHELPER#
2828

29+
# If systemd is running try starting qubes-admin-authzd even if the user
30+
# blocked the normal start by dh (above) via policy-rc.d. Not running it will
31+
# break passwordless auth, so this is most likely not what the user wanted. But
32+
# if they really want to they still can mask the service.
33+
34+
if [[ -e /run/systemd/system ]] &&
35+
! systemctl is-active --quiet qubes-admin-authzd.service &&
36+
systemctl is-enabled --quiet qubes-admin-authzd.service
37+
then
38+
systemctl start qubes-admin-authzd.service || true
39+
fi
40+
2941
exit 0
3042

3143
# vim: set ts=4 sw=4 sts=4 et :

debian/rules

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ override_dh_fixperms:
3737
dh_fixperms -a -Xqfile-unpacker
3838

3939
override_dh_systemd_start:
40-
dh_systemd_start --no-restart-on-upgrade
40+
dh_systemd_start --package=qubes-core-agent-passwordless-root --restart-after-upgrade
41+
dh_systemd_start --remaining-packages --no-restart-after-upgrade
4142

4243
override_dh_install:
4344
if [ "$(DISTRIBUTION)" = "Ubuntu" ]; then \

passwordless-root/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pam_qubes_admin_authz.so
2+
qubes-admin-authzd
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# This will be re-preset on package upgrade. If you really want you can
2+
# override this with a higher higher-priority preset file but that is probably
3+
# a bad idea since it will break the pam module.
4+
enable qubes-admin-authzd.service

passwordless-root/Makefile

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1+
BINDIR ?= /usr/bin
12
SYSCONFDIR ?= /etc
23
SUDOERSDIR = $(SYSCONFDIR)/sudoers.d
3-
POLKIT1DIR = $(SYSCONFDIR)/polkit-1
44
PAMDIR = $(SYSCONFDIR)/pam.d
55
PAMCONFIGSDIR = /usr/share/pam-configs/
6+
SYSLIBDIR ?= /lib
67

7-
.PHONY: install install-debian install-rh
8+
ifneq ($(DEB_HOST_MULTIARCH),)
9+
PAM_MOD_DIR = /usr/lib/$(DEB_HOST_MULTIARCH)/security
10+
else
11+
PAM_MOD_DIR = /usr/lib64/security
12+
endif
13+
14+
.PHONY: install install-debian install-rh all
15+
16+
all: qubes-admin-authzd pam_qubes_admin_authz.so
17+
18+
qubes-admin-authzd: qubes-admin-authzd.c qubes-admin-authz-common.h
19+
gcc -O2 -Wall -Wextra -Werror -fPIC -pie $< -o $@
20+
21+
pam_qubes_admin_authz.so: pam_qubes_admin_authz.c qubes-admin-authz-common.h
22+
gcc -O2 -Wall -Wextra -Werror -fPIC -pie -shared $< -o $@ -lpam
823

924
install:
1025
install -d -m 0750 $(DESTDIR)$(SUDOERSDIR)
@@ -14,11 +29,36 @@ install:
1429
sed -E '/^[^#]/s/\<(ROLE|TYPE)=[A-Za-z0-9_]+[[:space:]]+//g' qubes.sudoers | \
1530
install -D -m 0440 /dev/stdin $(DESTDIR)$(SUDOERSDIR)/qubes; \
1631
fi
17-
install -d -m 0750 $(DESTDIR)$(POLKIT1DIR)/rules.d
18-
install -D -m 0644 polkit-1-qubes-allow-all.rules $(DESTDIR)$(POLKIT1DIR)/rules.d/00-qubes-allow-all.rules
32+
install -D -t $(DESTDIR)$(PAM_MOD_DIR) pam_qubes_admin_authz.so
33+
install -D -t $(DESTDIR)$(BINDIR) qubes-admin-authzd
34+
install -D -m 0644 -t $(DESTDIR)$(SYSLIBDIR)/systemd/system qubes-admin-authzd.service
35+
install -D -m 0644 -t $(DESTDIR)$(SYSCONFDIR)/qubes/ admin-authzd.conf
36+
install -D -m 0644 -t $(DESTDIR)/usr/share/doc/qubes-core-agent-passwordless-root README.md
1937

2038
install-rh:
21-
install -D -m 0644 pam.d_su.qubes $(DESTDIR)$(PAMDIR)/su.qubes
39+
install -D -m 0644 -t $(DESTDIR)$(SYSLIBDIR)/systemd/system-preset 75-qubes-admin-authz.preset
40+
install -d $(DESTDIR)/usr/share/authselect/vendor
41+
for i in \
42+
local \
43+
nis \
44+
sssd \
45+
winbind \
46+
; do \
47+
install -D -t $(DESTDIR)/usr/share/authselect/vendor/$$i \
48+
authselect/$$i/system-auth authselect/$$i/password-auth || exit 1; \
49+
for j in \
50+
README \
51+
REQUIREMENTS \
52+
dconf-db \
53+
dconf-locks \
54+
fingerprint-auth \
55+
nsswitch.conf \
56+
postlogin \
57+
smartcard-auth \
58+
; do \
59+
ln -s ../../default/$$i/$$j $(DESTDIR)/usr/share/authselect/vendor/$$i/$$j || exit 1; \
60+
done; \
61+
done
2262

2363
install-debian:
24-
install -D -m 0644 pam-configs_su.qubes $(DESTDIR)$(PAMCONFIGSDIR)/su.qubes
64+
install -D -m 0644 pam-configs-qubes-admin-authz $(DESTDIR)$(PAMCONFIGSDIR)/qubes-admin-authz

passwordless-root/README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Passwordless in-qubqube admin authorization
2+
3+
By default all users in the `qubes` group (usually only the standard `user`
4+
user) are allowed to execute things as root via sudo/su/pkexec. This is allowed
5+
without a password prompt.
6+
7+
Separating the user isn't that meaningfull since Qubes' primary
8+
compartimentalization layer are qubes and `user` in a qube has access most
9+
things there anyway (user data, GUI I/O, etc). But some advanced users want
10+
more options therefore this mechanism has been extended.
11+
12+
## Modes
13+
14+
There are 3 modes:
15+
16+
- `allow`: Always allow admin access.
17+
- `deny`: Always deny admin access.
18+
- `qrexec`: Make a qrexec call and use it's result to allow/deny. The main
19+
usage is to have a trivial qrexec service in dom0 and use the qrexex policy
20+
with the ask action to allow only after prompting.
21+
22+
"Admin access" here means being able to run things as another user (including
23+
root), via sudo, su and polkit. This is always limited to users in the `qubes`
24+
group.
25+
26+
27+
## Config
28+
29+
When the `qubes-core-agent-passwordless-root` is installed the
30+
pam_qubes_admin_authz.so is always enabled. This module asks the
31+
`qubes-admin-authzd` daemon which does the actual logic (see below for
32+
technical details).
33+
34+
The mode can be set via /usr/local/etc/qubes/admin-authzd.conf for per-qube
35+
setting or more common via /etc/qubes/admin-authzd.conf in a template (setting
36+
in /usr/local has precendce).
37+
38+
There config file have a very simpley syntax. The first line needs to contain
39+
one of the listed mode above without anythings else. Currently the rest of the
40+
file is ignored. Please prefix comments with `#` to allow extension of this
41+
configuration file should the need arise.
42+
43+
44+
## qrexec policy
45+
46+
After setting the mode to qrexec, you need to configure the qrexec policy in
47+
dom0. For example:
48+
49+
```
50+
qubes.AuthorizeInVMAdminAccess * * @default ask target=dom0 default_target=dom0
51+
```
52+
53+
asks for requests from any VM.
54+
55+
Note that in dom0 only a trivial service is run that returns a fixed string
56+
such that the qube knows the result of the policy evaluation. The idea here is
57+
that this way the existing qrexec policy can be reused, including it's ask
58+
prompt.
59+
60+
61+
## Limitaions
62+
63+
Keep in mind that if you have allowed admin access and the qube was compromised
64+
at that point persistence is trivial.
65+
66+
67+
## Technical details
68+
69+
We implement a PAM module named `pam_qubes_admin_authz.so` to permit the
70+
access. Since PAM modules can be run in a setuid context (when called by
71+
sudo/su) we want to keep the code simple there. Therefore we use just some
72+
existing PAM helper functions to check for the requsting users group membership
73+
and check the PAM "service" (`sudo`, `su-l`, etc.) and if they match we make a
74+
connection to an abstract unix socket. With `SO_PEERCRED` we check that this
75+
socket has been opened by root. The rest, including config file handling and
76+
invoking qrexec-client-vm is then handled by the `qubes-admin-authzd` at the
77+
other end of the socket (started by qubes-admin-authzd.service).
78+
79+
## Recovery
80+
81+
Should you have locked you self out you should still be able to use
82+
`qvm-console-dispvm` and login as root there without a password.

0 commit comments

Comments
 (0)