diff --git a/pkgbuilds/omarchy-dev/PKGBUILD b/pkgbuilds/omarchy-dev/PKGBUILD index 58630edde..8c83f9f77 100644 --- a/pkgbuilds/omarchy-dev/PKGBUILD +++ b/pkgbuilds/omarchy-dev/PKGBUILD @@ -18,7 +18,7 @@ conflicts=('omarchy') depends=( # Omarchy meta 'omarchy-keyring' - 'omarchy-settings-dev' + "omarchy-settings-dev=${pkgver}-${pkgrel}" # Wayland / Hyprland core 'hyprland' @@ -108,7 +108,8 @@ prepare() { package() { cd "$srcdir/omarchy" - # Runtime binaries — ship everything in bin/ except the debug helpers + # Runtime binaries — settings owns diagnostics and the sudo grant lifecycle. + # Ship everything in bin/ except those support helpers # that ship from omarchy-settings (needed before omarchy is installed, # e.g. on the ISO live env). install -d "$pkgdir/usr/bin" "$pkgdir/usr/share/omarchy/bin" @@ -117,7 +118,7 @@ package() { local base base=$(basename "$bin") case "$base" in - omarchy-debug|omarchy-debug-idle|omarchy-upload-log) + omarchy-debug|omarchy-debug-idle|omarchy-upload-log|omarchy-sudo-passwordless|omarchy-security-functions) continue ;; esac diff --git a/pkgbuilds/omarchy-settings-dev/PKGBUILD b/pkgbuilds/omarchy-settings-dev/PKGBUILD index 6c7f8d987..928be1526 100644 --- a/pkgbuilds/omarchy-settings-dev/PKGBUILD +++ b/pkgbuilds/omarchy-settings-dev/PKGBUILD @@ -31,6 +31,7 @@ depends=( 'bash' 'curl' 'gum' + 'sudo' 'hicolor-icon-theme' 'plymouth' ) @@ -38,6 +39,8 @@ depends=( makedepends=( 'git' 'imagemagick' + 'gcc' + 'binutils' ) # backup=() is pacman's hook for protecting user edits to package-owned files @@ -140,9 +143,31 @@ prepare() { fi } +build() { + cd "$srcdir/omarchy" + + # Static PIE starts without a caller-selected dynamic loader or preload. + cc $CFLAGS -std=c11 -O2 -Wall -Wextra -Werror -fstack-protector-strong \ + -D_FORTIFY_SOURCE=3 default/omarchy/security/omarchy-debug-launcher.c \ + $LDFLAGS -static-pie -Wl,-z,relro,-z,now -o "$srcdir/omarchy-debug" +} + +check() { + local headers dynamic + headers=$(readelf -W -l "$srcdir/omarchy-debug") || return 1 + dynamic=$(readelf -W -d "$srcdir/omarchy-debug") || return 1 + [[ $headers != *INTERP* && $dynamic != *NEEDED* ]] || return 1 + awk '$1 == "GNU_STACK" { found = 1; if ($7 != "RW") exit 1 } END { if (!found) exit 1 }' <<< "$headers" || return 1 + [[ -f $srcdir/omarchy/bin/omarchy-debug && + -f $srcdir/omarchy/default/omarchy/command-metadata/omarchy-debug ]] +} + package() { cd "$srcdir/omarchy" + # Abort before grant expiry support disappears if policy revocation fails. + install -Dm644 default/libalpm/hooks/05-omarchy-passwordless-revoke.hook "$pkgdir/usr/share/libalpm/hooks/05-omarchy-passwordless-revoke.hook" + # /etc/skel/.config from config/** — system-wide default user config. # Package-owned defaults that live elsewhere in the system belong under # default/** or etc/** instead. @@ -395,9 +420,19 @@ EOF install -Dm644 default/tensaku/state.toml \ "$pkgdir/etc/skel/.local/state/tensaku/state.toml" + # Keep grant publication, its shared library and boot cleanup in one + # package. Removing only the desktop runtime must not remove expiry code. + for helper in omarchy-sudo-passwordless omarchy-security-functions; do + install -Dm755 "bin/$helper" "$pkgdir/usr/bin/$helper" + install -d "$pkgdir/usr/share/omarchy/bin" + ln -s "/usr/bin/$helper" "$pkgdir/usr/share/omarchy/bin/$helper" + done + # Support binaries needed before the full omarchy package is installed # (used by ISO/recovery flows). install -Dm755 bin/omarchy-upload-log "$pkgdir/usr/bin/omarchy-upload-log" - install -Dm755 bin/omarchy-debug "$pkgdir/usr/bin/omarchy-debug" + install -Dm755 "$srcdir/omarchy-debug" "$pkgdir/usr/bin/omarchy-debug" + install -Dm755 bin/omarchy-debug "$pkgdir/usr/lib/omarchy/omarchy-debug-collector" + install -Dm644 default/omarchy/command-metadata/omarchy-debug "$pkgdir/usr/share/omarchy/command-metadata/omarchy-debug" install -Dm755 bin/omarchy-debug-idle "$pkgdir/usr/bin/omarchy-debug-idle" } diff --git a/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install b/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install index 19f54e705..317b24f54 100644 --- a/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install +++ b/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install @@ -1,3 +1,43 @@ +# This lock and removal marker are shared with omarchy-sudo-passwordless. +# Keep the marker through removal so no grant can be published after its boot +# cleanup prerequisite disappears. A completed installation clears it again. +_passwordless_package_transition() ( + local action=$1 lock_fd directory + [[ -d /run && ! -L /run && -d /run/lock && ! -L /run/lock ]] || return 1 + for directory in /run /run/lock; do + [[ $(/usr/bin/stat -Lc '%u' "$directory") == "0" ]] || return 1 + ! (( 8#$(/usr/bin/stat -Lc '%a' "$directory") & 022 )) || return 1 + done + umask 077 + exec {lock_fd}>/run/lock/omarchy-sudo-passwordless.lock || return 1 + /usr/bin/flock -x "$lock_fd" || return 1 + case "$action" in + begin) + : >/run/omarchy-sudo-passwordless-package-removing || return 1 + /usr/bin/rm -f -- /etc/sudoers.d/99-omarchy-nopasswd-* || return 1 + ;; + removed) + /usr/bin/rm -f -- /etc/sudoers.d/99-omarchy-nopasswd-* || return 1 + ;; + installed) + [[ -f /etc/tmpfiles.d/omarchy-nopasswd-sudo.conf ]] || return 1 + /usr/bin/rm -f -- /run/omarchy-sudo-passwordless-package-removing || return 1 + ;; + *) return 1 ;; + esac +) + +pre_remove() { + _passwordless_package_transition begin || { + echo "ERROR: Could not revoke temporary Omarchy sudo grants before removing their boot cleanup. Administrator cleanup is required." >&2 + return 1 + } +} + +pre_upgrade() { + pre_remove +} + _apple_silicon() { [[ $(uname -m) == aarch64 ]] && grep -aq 'apple,' /proc/device-tree/compatible 2>/dev/null } @@ -56,9 +96,17 @@ _etc_overrides_apply() { } post_install() { - _etc_overrides_apply + _etc_overrides_apply || return 1 + _passwordless_package_transition installed } post_upgrade() { - _etc_overrides_apply + post_install +} + +post_remove() { + _passwordless_package_transition removed || { + echo "ERROR: Temporary Omarchy sudo grants could not be removed. Administrator cleanup is required." >&2 + return 1 + } } diff --git a/pkgbuilds/omarchy-settings/PKGBUILD b/pkgbuilds/omarchy-settings/PKGBUILD index f466293f1..836de0b4e 100644 --- a/pkgbuilds/omarchy-settings/PKGBUILD +++ b/pkgbuilds/omarchy-settings/PKGBUILD @@ -13,7 +13,7 @@ pkgname='omarchy-settings' _tag='' _commit='346e69e1cec6c4e8924531874af6ba010a1bc99e' pkgver=4.0.2 -pkgrel=1 +pkgrel=3 pkgdesc='Omarchy user defaults, /etc/skel content, fonts, plymouth theme, and support helpers' # Arch-specific because the shipped /etc tree is not the same on every # architecture: the Limine, mkinitcpio, zram and oomd drop-ins belong to the @@ -40,6 +40,7 @@ depends=( 'bash' 'curl' 'gum' + 'sudo' 'hicolor-icon-theme' 'plymouth' ) @@ -47,6 +48,8 @@ depends=( makedepends=( 'git' 'imagemagick' + 'gcc' + 'binutils' ) # backup=() is pacman's hook for protecting user edits to package-owned files @@ -135,9 +138,31 @@ prepare() { fi } +build() { + cd "$srcdir/omarchy" + + # Static PIE starts without a caller-selected dynamic loader or preload. + cc $CFLAGS -std=c11 -O2 -Wall -Wextra -Werror -fstack-protector-strong \ + -D_FORTIFY_SOURCE=3 default/omarchy/security/omarchy-debug-launcher.c \ + $LDFLAGS -static-pie -Wl,-z,relro,-z,now -o "$srcdir/omarchy-debug" +} + +check() { + local headers dynamic + headers=$(readelf -W -l "$srcdir/omarchy-debug") || return 1 + dynamic=$(readelf -W -d "$srcdir/omarchy-debug") || return 1 + [[ $headers != *INTERP* && $dynamic != *NEEDED* ]] || return 1 + awk '$1 == "GNU_STACK" { found = 1; if ($7 != "RW") exit 1 } END { if (!found) exit 1 }' <<< "$headers" || return 1 + [[ -f $srcdir/omarchy/bin/omarchy-debug && + -f $srcdir/omarchy/default/omarchy/command-metadata/omarchy-debug ]] +} + package() { cd "$srcdir/omarchy" + # Abort before grant expiry support disappears if policy revocation fails. + install -Dm644 default/libalpm/hooks/05-omarchy-passwordless-revoke.hook "$pkgdir/usr/share/libalpm/hooks/05-omarchy-passwordless-revoke.hook" + # /etc/skel/.config from config/** — system-wide default user config. # Package-owned defaults that live elsewhere in the system belong under # default/** or etc/** instead. @@ -393,9 +418,19 @@ EOF install -Dm644 default/tensaku/state.toml \ "$pkgdir/etc/skel/.local/state/tensaku/state.toml" + # Keep grant publication, its shared library and boot cleanup in one + # package. Removing only the desktop runtime must not remove expiry code. + for helper in omarchy-sudo-passwordless omarchy-security-functions; do + install -Dm755 "bin/$helper" "$pkgdir/usr/bin/$helper" + install -d "$pkgdir/usr/share/omarchy/bin" + ln -s "/usr/bin/$helper" "$pkgdir/usr/share/omarchy/bin/$helper" + done + # Support binaries needed before the full omarchy package is installed # (used by ISO/recovery flows). install -Dm755 bin/omarchy-upload-log "$pkgdir/usr/bin/omarchy-upload-log" - install -Dm755 bin/omarchy-debug "$pkgdir/usr/bin/omarchy-debug" + install -Dm755 "$srcdir/omarchy-debug" "$pkgdir/usr/bin/omarchy-debug" + install -Dm755 bin/omarchy-debug "$pkgdir/usr/lib/omarchy/omarchy-debug-collector" + install -Dm644 default/omarchy/command-metadata/omarchy-debug "$pkgdir/usr/share/omarchy/command-metadata/omarchy-debug" install -Dm755 bin/omarchy-debug-idle "$pkgdir/usr/bin/omarchy-debug-idle" } diff --git a/pkgbuilds/omarchy-settings/omarchy-settings.install b/pkgbuilds/omarchy-settings/omarchy-settings.install index 4ebb226d7..a42fce0c9 100644 --- a/pkgbuilds/omarchy-settings/omarchy-settings.install +++ b/pkgbuilds/omarchy-settings/omarchy-settings.install @@ -1,3 +1,43 @@ +# This lock and removal marker are shared with omarchy-sudo-passwordless. +# Keep the marker through removal so no grant can be published after its boot +# cleanup prerequisite disappears. A completed installation clears it again. +_passwordless_package_transition() ( + local action=$1 lock_fd directory + [[ -d /run && ! -L /run && -d /run/lock && ! -L /run/lock ]] || return 1 + for directory in /run /run/lock; do + [[ $(/usr/bin/stat -Lc '%u' "$directory") == "0" ]] || return 1 + ! (( 8#$(/usr/bin/stat -Lc '%a' "$directory") & 022 )) || return 1 + done + umask 077 + exec {lock_fd}>/run/lock/omarchy-sudo-passwordless.lock || return 1 + /usr/bin/flock -x "$lock_fd" || return 1 + case "$action" in + begin) + : >/run/omarchy-sudo-passwordless-package-removing || return 1 + /usr/bin/rm -f -- /etc/sudoers.d/99-omarchy-nopasswd-* || return 1 + ;; + removed) + /usr/bin/rm -f -- /etc/sudoers.d/99-omarchy-nopasswd-* || return 1 + ;; + installed) + [[ -f /etc/tmpfiles.d/omarchy-nopasswd-sudo.conf ]] || return 1 + /usr/bin/rm -f -- /run/omarchy-sudo-passwordless-package-removing || return 1 + ;; + *) return 1 ;; + esac +) + +pre_remove() { + _passwordless_package_transition begin || { + echo "ERROR: Could not revoke temporary Omarchy sudo grants before removing their boot cleanup. Administrator cleanup is required." >&2 + return 1 + } +} + +pre_upgrade() { + pre_remove +} + _apple_silicon() { [[ $(uname -m) == aarch64 ]] && grep -aq 'apple,' /proc/device-tree/compatible 2>/dev/null } @@ -56,9 +96,17 @@ _etc_overrides_apply() { } post_install() { - _etc_overrides_apply + _etc_overrides_apply || return 1 + _passwordless_package_transition installed } post_upgrade() { - _etc_overrides_apply + post_install +} + +post_remove() { + _passwordless_package_transition removed || { + echo "ERROR: Temporary Omarchy sudo grants could not be removed. Administrator cleanup is required." >&2 + return 1 + } } diff --git a/pkgbuilds/omarchy/PKGBUILD b/pkgbuilds/omarchy/PKGBUILD index 2e20a38db..f333cbae2 100644 --- a/pkgbuilds/omarchy/PKGBUILD +++ b/pkgbuilds/omarchy/PKGBUILD @@ -13,7 +13,7 @@ pkgname='omarchy' _tag='' _commit='346e69e1cec6c4e8924531874af6ba010a1bc99e' pkgver=4.0.2 -pkgrel=1 +pkgrel=3 pkgdesc='Beautiful, modern, and opinionated Arch Linux by DHH' # The payload is architecture-independent, but the dependency set is not: the # boot stack differs per architecture (see depends_x86_64 / depends_aarch64), @@ -32,7 +32,7 @@ depends=( # package satisfy it, leaving a mixed dev/stable install. A versioned # dependency can only be satisfied by the real omarchy-settings built # from the same _commit, and forces the pair to upgrade together. - "omarchy-settings=${pkgver}" + "omarchy-settings=${pkgver}-${pkgrel}" # Wayland / Hyprland core 'hyprland' @@ -108,7 +108,8 @@ prepare() { package() { cd "$srcdir/omarchy" - # Runtime binaries — ship everything in bin/ except the debug helpers + # Runtime binaries — settings owns diagnostics and the sudo grant lifecycle. + # Ship everything in bin/ except those support helpers # that ship from omarchy-settings (needed before omarchy is installed, # e.g. on the ISO live env). install -d "$pkgdir/usr/bin" "$pkgdir/usr/share/omarchy/bin" @@ -117,7 +118,7 @@ package() { local base base=$(basename "$bin") case "$base" in - omarchy-debug|omarchy-debug-idle|omarchy-upload-log) + omarchy-debug|omarchy-debug-idle|omarchy-upload-log|omarchy-sudo-passwordless|omarchy-security-functions) continue ;; esac