Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions build/desktop/dwl-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }

/* commands: zone launches, where --ask has the chrome prompt for a passphrase
* if the zone needs one, and the chrome's own menu, a text program that needs
* a zone 0 terminal of its own, as its window at login has */
/* commands: zone launches (the chrome asks for a passphrase if needed) and the
* chrome's menu, a text program in a zone 0 terminal of its own */
static const char *termcmd[] = { "kryptik-launch", "--ask", "work", "--", "havoc", NULL };
static const char *personalcmd[] = { "kryptik-launch", "--ask", "personal", "--", "havoc", NULL };
static const char *untrustedcmd[] = { "kryptik-launch", "--ask", "untrusted", "--", "havoc", "lynx", NULL };
Expand Down
14 changes: 7 additions & 7 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ A zone is the unit of isolation, and every process belongs to exactly one.
The trusted base, like Qubes' `dom0`: PID 1, the services, kryptikd, the
compositor and the desktop session. It has no route out and runs no user
applications (ADR-003), which the desktop suite checks process by process.
kryptikd creates the other zones as root; unprivileged
user namespaces are off ([privileged launch](design/privileged-launch.md)).
kryptikd creates the other zones as root; unprivileged user namespaces are
off ([privileged launch](design/privileged-launch.md)).

### Shipped zones

Expand Down Expand Up @@ -52,11 +52,11 @@ The chrome's menu is its menu window.

## Between zones

Nothing crosses by default. The broker in kryptikd identifies a caller by its
socket's peer uid and carries two things ([broker](design/broker.md)): a file
transfer, one file one way to a zone the sender's policy names, after the user
approves it; and the clipboard, one per zone, moved between zones only by a
user gesture in zone 0.
Nothing crosses by default. The [broker](design/broker.md) in kryptikd
identifies a caller by its socket's peer uid and carries two things. A file
transfer sends one file, one way, to a zone listed in the sender's policy,
once the user approves it. Each zone has one clipboard, moved to another zone
only by a user gesture in zone 0.

Routed zones reach the network through isolated ports on the `net` zone's
bridge. The `net` zone can also send zone 0 a clock offset and releases, both
Expand Down
19 changes: 9 additions & 10 deletions tools/desktop/dwl-zone-borders.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"""

EDITS = [
# (1) Client: the zone's colour, the band that marks it unfocused, the bar.
# Client: the zone's colour, the band that marks it unfocused, the bar.
(""" struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
""",
""" struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
Expand All @@ -114,7 +114,7 @@
struct wlr_scene_rect *bands[4]; /* top, bottom, left, right */
struct wlr_scene_tree *bar; /* Kryptik: names the zone above a fullscreen window */
"""),
# (2) The ZoneColor type, beside Rule so config.h can define the table.
# The ZoneColor type, beside Rule so config.h can define the table.
("""typedef struct {
const char *id;
const char *title;
Expand All @@ -136,7 +136,7 @@
const float border[4];
} ZoneColor;
"""),
# (3) The chooser, defined before applyrules (its first neighbour).
# The chooser, placed before applyrules.
("""void
applyrules(Client *c)
{
Expand Down Expand Up @@ -173,7 +173,7 @@
applyrules(Client *c)
{
"""),
# (4) mapnotify: zone-coloured borders, then the band over them as four
# mapnotify: zone-coloured borders, then the band over them as four
# strips. The surface stays below both, or a buffer larger than its
# configure would paint over the right and bottom borders. A new window
# starts unfocused, so the band starts enabled; the bar starts hidden.
Expand All @@ -197,7 +197,7 @@
c->bar = wlr_scene_tree_create(c->scene);
wlr_scene_node_set_enabled(&c->bar->node, 0);
"""),
# (5) resize: the band is the ring of the border nearest the surface.
# resize: the band is the ring of the border nearest the surface.
(""" wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
""",
""" wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
Expand All @@ -210,7 +210,7 @@
wlr_scene_node_set_position(&c->bands[2]->node, c->bw - bandpx, c->bw);
wlr_scene_node_set_position(&c->bands[3]->node, c->geom.width - c->bw, c->bw);
"""),
# (6) focusclient: the colour is the zone's either way; focus hides the band.
# focusclient: the colour is the zone's either way; focus hides the band.
(""" if (!exclusive_focus && !seat->drag)
client_set_border_color(c, focuscolor);
""",
Expand All @@ -220,15 +220,15 @@
wlr_scene_node_set_enabled(&c->band->node, 0);
}
"""),
# (7) focusclient, the window losing focus: its band comes back.
# focusclient, the window losing focus: its band comes back.
(""" } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
client_set_border_color(old_c, bordercolor);
""",
""" } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
client_set_border_color(old_c, old_c->zoneborder);
wlr_scene_node_set_enabled(&old_c->band->node, 1);
"""),
# (8) setfullscreen: keep the border; dwl's 0 would let a window hide its zone.
# setfullscreen: keep the border; dwl's 0 would let a window hide its zone.
(""" c->bw = fullscreen ? 0 : borderpx;
client_set_fullscreen(c, fullscreen);
""",
Expand Down Expand Up @@ -464,8 +464,7 @@
\t\t\treturn c;
\t}
"""),
# setmon also chooses focus after mapping; preserve another zone's actual
# keyboard focus even when the selected monitor has changed.
# setmon also picks focus after mapping: keep another zone's keyboard focus across monitors.
("""\t\tsetfloating(c, c->isfloating);
\t}
\tfocusclient(focustop(selmon), 1);
Expand Down
46 changes: 18 additions & 28 deletions tools/desktop/kryptik-chrome
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,20 @@
# window, then launch (kryptik-launch hands
# over here when it has no terminal)
# kryptik-chrome --focus print the focused zone, from the record
# kryptik-chrome --confirm ID ask the broker's question ID in a trusted
# window and write back the answer: yes only
# kryptik-chrome --confirm ID ask the broker's question ID in a trusted window: yes only
# for the code it shows, typed after it shows
#
# Passphrases are read by kryptik-launch on the chrome's own terminal and go
# to the daemon as a descriptor, never in argv or the environment.

# The verified root's zone files, not /etc's: /etc is an overlay the state
# partition can shadow, and the labels shown must match the colours dwl draws.
# The verified root's zone files, which dwl's colours match: the state partition can shadow /etc.
ZONES=/usr/lib/kryptik/zones
LAUNCH=/usr/bin/kryptik-launch
# `havoc [option...] [program [args...]]`: no -e, and an unknown option makes
# it print its usage and exit.
# havoc takes the program as plain arguments: it has no -e, and exits on an unknown option.
TERMINAL=/usr/bin/havoc
RT="${XDG_RUNTIME_DIR:-/tmp}"
FOCUS="$RT/kryptik/focus"
# The last window from a zone. The menu shows this one: opening the menu
# focuses the menu, so the plain record would only ever name zone 0.
# The last zone window, for the menu: once the menu has focus, the focus record names zone 0.
FOCUS_ZONE="$RT/kryptik/focus.zone"
CONSENT=/run/kryptik-consent

Expand Down Expand Up @@ -99,28 +95,26 @@ run_status() {
mkdir -p "$RT/kryptik" 2>/dev/null
# The menu window, so a fresh session shows something usable.
"$TERMINAL" /usr/bin/kryptik-chrome --menu &
# The consent watcher: one trusted window per question the broker leaves.
# Holding watcher.lock exclusively tells the broker someone is here to ask
# (consent.rs refuses at once if it can take the lock shared); the kernel
# drops it when this subshell dies. Confirm windows must not inherit it,
# and a second session's watcher exits quietly.
# The consent watcher. Holding watcher.lock tells the broker someone is here
# to ask: consent.rs refuses at once if it can take the lock shared. The
# kernel drops it with this subshell, and a second session's watcher exits
# quietly.
(
exec 9> "$CONSENT/watcher.lock" 2>/dev/null || exit 0
flock -n 9 || exit 0
# From here a write creates, never follows or clobbers: any member of
# group kryptik can plant a link in the directory. That also makes the
# .dialog claim one exclusive create.
# Writes create, never follow or clobber: group kryptik can plant links here.
# That also makes each .dialog claim one exclusive create.
set -C
while :; do
for ask in "$CONSENT"/*.ask; do
[ -e "$ask" ] || continue
id="${ask##*/}"; id="${id%.ask}"
[ -e "$CONSENT/$id.dialog" ] && continue
: > "$CONSENT/$id.dialog" 2>/dev/null || continue
# A window must not hold the lock past the watcher's death.
"$TERMINAL" /usr/bin/kryptik-chrome --confirm "$id" 9>&- &
done
# A window writes its code and answer even for a question
# withdrawn meanwhile; whatever outlives its question goes.
# A window may write its code and answer after its question is withdrawn.
for f in "$CONSENT"/*.dialog "$CONSENT"/*.code "$CONSENT"/*.answer; do
[ -e "$f" ] || continue
[ -e "${f%.*}.ask" ] || rm -f "$f"
Expand Down Expand Up @@ -206,8 +200,7 @@ run_menu() {
b) set -- "$TERMINAL" /usr/bin/lynx ;;
esac
echo "launching in zone $z: $*"
# --ask: a passphrase is read on this zone 0 terminal,
# never on a zone's.
# --ask: a passphrase is read on this zone 0 terminal, never a zone's.
"$LAUNCH" --ask "$z" -- "$@" || sleep 3
;;
*) echo "?"; sleep 1 ;;
Expand Down Expand Up @@ -236,8 +229,7 @@ run_confirm() { # ID
# A question with no kind is a transfer.
kind="$(sed -n 's/^kind=//p' "$ask")"
if [ "$kind" = clock ]; then
# The clock (docs/design/time.md): the network's time is too far from
# this machine's to accept unasked. Only the user, with a watch, can say.
# The network's time is too far from this machine's to accept unasked (docs/design/time.md).
now="$(sed -n 's/^now=//p' "$ask")"; proposed="$(sed -n 's/^proposed=//p' "$ask")"
sources="$(sed -n 's/^sources=//p' "$ask")"
echo "================ KRYPTIK - set the clock? (zone 0) ================"
Expand Down Expand Up @@ -274,21 +266,19 @@ run_confirm() { # ID
[ "$(cat | wc -c)" -eq 0 ] || echo "(what was typed before this question showed is ignored)"
stty "$was"
fi
# The answer is a code drawn for this question alone: no zone sees this
# window, so none can type it. It is kept beside the question for zone 0's
# tests; whatever can read this directory could write the answer anyway.
# Writes here create, never follow or clobber: any member of group kryptik
# can plant a link in the directory. An answer that cannot be written is
# no answer, which the broker takes as a refusal.
# Writes create, never follow or clobber: any member of group kryptik can plant a link.
set -C
# A code for this question alone: no zone sees this window, so none can type it.
code=$(( $(od -An -N1 -tu1 /dev/urandom) % 90 + 10 ))
# Kept for zone 0's tests; whatever can read it could write the answer anyway.
(umask 077; printf '%s\n' "$code" > "$CONSENT/$id.code") 2>/dev/null \
|| echo "kryptik-chrome --confirm $id: the code could not be written beside the question" >> "$RT/kryptik/session.log"
printf 'Type %s and Enter to allow; anything else refuses: ' "$code"
answer=no
if read -r reply; then
[ "$reply" = "$code" ] && answer=yes
fi
# An answer that cannot be written is none: the broker takes that as a refusal.
if printf '%s\n' "$answer" > "$CONSENT/$id.answer.tmp" && mv -f "$CONSENT/$id.answer.tmp" "$CONSENT/$id.answer"; then
echo "-> $answer"
else
Expand Down
Loading