From patchwork Sun Dec 24 17:01:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "ashish.is--- via Guix-patches\" via" X-Patchwork-Id: 58037 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id E3C6D27BBE2; Sun, 24 Dec 2023 19:25:13 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HTML_MESSAGE,MAILING_LIST_MULTI,SPF_HELO_PASS, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 0D74527BBE9 for ; Sun, 24 Dec 2023 19:25:11 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rHU5T-0003PM-6U; Sun, 24 Dec 2023 14:24:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rHRsO-0003nK-S6 for guix-patches@gnu.org; Sun, 24 Dec 2023 12:02:56 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rHRsO-0001yU-Jj for guix-patches@gnu.org; Sun, 24 Dec 2023 12:02:56 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rHRsU-0004RP-99 for guix-patches@gnu.org; Sun, 24 Dec 2023 12:03:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#68007] [PATCH] services: Add doas service. Resent-From: lgcoelho@disroot.org Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 24 Dec 2023 17:03:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 68007 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 68007@debbugs.gnu.org X-Debbugs-Original-To: guix-patches@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.170343732916989 (code B ref -1); Sun, 24 Dec 2023 17:03:02 +0000 Received: (at submit) by debbugs.gnu.org; 24 Dec 2023 17:02:09 +0000 Received: from localhost ([127.0.0.1]:53462 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rHRrc-0004Pv-H9 for submit@debbugs.gnu.org; Sun, 24 Dec 2023 12:02:09 -0500 Received: from lists.gnu.org ([2001:470:142::17]:52166) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rHRrX-0004PM-Mk for submit@debbugs.gnu.org; Sun, 24 Dec 2023 12:02:07 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rHRrI-0001UV-Dm for guix-patches@gnu.org; Sun, 24 Dec 2023 12:01:48 -0500 Received: from layka.disroot.org ([178.21.23.139]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rHRrC-0001ka-P8 for guix-patches@gnu.org; Sun, 24 Dec 2023 12:01:48 -0500 Received: from localhost (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 80EB1413FA for ; Sun, 24 Dec 2023 18:01:38 +0100 (CET) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Bkrxd0zKvkhu for ; Sun, 24 Dec 2023 18:01:37 +0100 (CET) MIME-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1703437293; bh=IAz2S+OMW4sRMrUdQXCOgLDRrNM+ZAnniRApYaC39p4=; h=Date:From:To:Subject; b=URP/JP0vwrNRwyH6iMjrtUf7Y5AMg9hDNSHzg1kYHVwoNCFTAjX6tTzQ6J2o2wGHD 1Q4C2jsq8DBl75hueNo26DqSe7sw00rpnyXG/pdEaIHVN7JUblFYnypbP5KyEzs1lh POWkCXXOqgt+aZkMw5cPUIrgaa7ctfUha18NLQlppnzRJaWmnZ5zHjtawx8JqOC0QF z3GzedgUj13pwXtLDIIrcfnl9KfoZt0SGjb+38o4zYBKAu/+F9g6DMWDRDffpVBLoG XDAH3AL47cPVM1bCIakIl6F1C6oLMH0DlLKhZhJTBhIsRyZwDIJIHqiQNEGoM8Br4h 2aH0fLcAXuNfQ== Date: Sun, 24 Dec 2023 17:01:33 +0000 Message-ID: <34bf485ff6eb60d88c21629fd7ef768a@disroot.org> X-Sender: lgcoelho@disroot.org Received-SPF: pass client-ip=178.21.23.139; envelope-from=lgcoelho@disroot.org; helo=layka.disroot.org X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-Mailman-Approved-At: Sun, 24 Dec 2023 14:24:33 -0500 X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: lgcoelho@disroot.org X-ACL-Warn: , lgcoelho--- via Guix-patches X-Patchwork-Original-From: lgcoelho--- via Guix-patches via From: "ashish.is--- via Guix-patches\" via" Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches This service enables declarative description of doas.conf. A simple example would be --8<---------------cut here-------------------------------------------------end--------------->8--- (simple-service 'miscellaneous-permissions doas-service-type (list (permit (identity ":wheel") (setenv `(("GUILE_LOAD_PATH" . #t)))) (permit (identity ":wheel") (nopass? #t) (command "guix") (args `("pull"))))) (simple-service 'text-editors-permissions doas-service-type (map (lambda (cmd) (permit (identity ":wheel") (keepenv? #t) (command cmd))) `("kak" "emacsclient"))) (simple-service 'power-management-permissions doas-service-type (map (lambda (cmd) (permit (identity ":wheel") (nopass? #t) (command cmd) (args '()))) `("zzz" "halt" "reboot"))) (simple-service 'shepherd-status-permissions doas-service-type (map (lambda (action) (permit (identity ":wheel") (nopass? #t) (command "herd") (args (list action)))) `("status" "detailed-status"))) (simple-service 'service-management-permissions doas-service-type (flat-map (lambda (service action) (permit (identity ":wheel") (nopass? #t) (command "herd") (args (map symbol->string (list action service))))) '(tor networking wpa-supplicant) '(doc stop start enable status restart disable))) --8<---------------cut here-------------------------------------------------end--------------->8--- This generates the following configuration file: --8<---------------cut here-------------------------------------------------end--------------->8--- permit setenv { GUILE_LOAD_PATH } permit nopass :wheel cmd guix args pull permit keepenv :wheel cmd kak permit keepenv :wheel cmd emacsclient permit nopass :wheel cmd zzz args permit nopass :wheel cmd halt args permit nopass :wheel cmd reboot args permit nopass :wheel cmd herd args status permit nopass :wheel cmd herd args detailed-status permit nopass :wheel cmd herd args doc tor permit nopass :wheel cmd herd args stop tor permit nopass :wheel cmd herd args start tor permit nopass :wheel cmd herd args enable tor permit nopass :wheel cmd herd args status tor permit nopass :wheel cmd herd args restart tor permit nopass :wheel cmd herd args disable tor permit nopass :wheel cmd herd args doc networking permit nopass :wheel cmd herd args stop networking permit nopass :wheel cmd herd args start networking permit nopass :wheel cmd herd args enable networking permit nopass :wheel cmd herd args status networking permit nopass :wheel cmd herd args restart networking permit nopass :wheel cmd herd args disable networking permit nopass :wheel cmd herd args doc wpa-supplicant permit nopass :wheel cmd herd args stop wpa-supplicant permit nopass :wheel cmd herd args start wpa-supplicant permit nopass :wheel cmd herd args enable wpa-supplicant permit nopass :wheel cmd herd args status wpa-supplicant permit nopass :wheel cmd herd args restart wpa-supplicant permit nopass :wheel cmd herd args disable wpa-supplicant --8<---------------cut here-------------------------------------------------end--------------->8--- From df03ab95649efe2e2b3ee9ad8e31518206eb6a68 Mon Sep 17 00:00:00 2001 From: Luis Guilherme Coelho Date: Sun, 24 Dec 2023 13:27:36 -0300 Subject: [PATCH] services: Add doas service. --- gnu/services/admin.scm | 174 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/gnu/services/admin.scm b/gnu/services/admin.scm index 0b325fddb1..5bb598300e 100644 --- a/gnu/services/admin.scm +++ b/gnu/services/admin.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2016-2023 Ludovic Courtès ;;; Copyright © 2020 Brice Waegeneire ;;; Copyright © 2023 Giacomo Leidi +;;; Copyright © 2023 Luis Guilherme Coelho ;;; ;;; This file is part of GNU Guix. ;;; @@ -37,6 +38,8 @@ (define-module (gnu services admin) #:use-module (guix packages) #:use-module (guix records) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (ice-9 format) #:use-module (ice-9 match) #:use-module (ice-9 vlist) #:export (%default-rotations @@ -93,7 +96,29 @@ (define-module (gnu services admin) unattended-upgrade-configuration-services-to-restart unattended-upgrade-configuration-system-expiration unattended-upgrade-configuration-maximum-duration - unattended-upgrade-configuration-log-file)) + unattended-upgrade-configuration-log-file + + doas-service-type + + permit + make-permit-statement + permit-statement? + permit-statement-args + permit-statement-as-user + permit-statement-command + permit-statement-identity + permit-statement-keepenv? + permit-statement-nolog? + permit-statement-nopass? + permit-statement-persist? + permit-statement-setenv + + deny + make-deny-statement + deny-statement? + deny-statement-args + deny-statement-as-user + deny-statement-command)) ;;; Commentary: ;;; @@ -537,4 +562,151 @@ (define unattended-upgrade-service-type "Periodically upgrade the system from the current configuration.") (default-value (unattended-upgrade-configuration)))) + +;;; +;;; Doas configuration. +;;; + +;; Dummy serializers, just to avoid warnings +(define empty-serializer + (@@ (gnu services configuration) empty-serializer)) +(define serialize-string empty-serializer) +(define serialize-list-of-strings empty-serializer) + +(define assoc-list? (list-of pair?)) +(define (serialize-assoc-list field-name val) + (map (match-lambda + ((var . #t) var) + ((var . #f) (string-append "-" var)) + ((var . value) (format #f "~a=~a" var value))) + val)) +(define-maybe list-of-strings) +(define-maybe assoc-list) +(define-maybe string) + +(define-configuration/no-serialization permit-statement + (nopass? + (boolean #f) + "Whether the user should be permitted to run the command without a password.") + (nolog? + (boolean #f) + "Wheter sucessful command exection should be logged.") + (persist? + (boolean #f) + "After the user sucessfully authenticates, do not ask for a password again +for some time.") + (keepenv? + (boolean #f) + "Wheter environment variables other than those listed in doas should be +retained when creating the enviroment for the new process.") + (identity + string + "The username to match. Groups may be specified by prepending a colon ':'.") + (as-user + maybe-string + "The target user the running user is allowed to run the command as. The +default is all users.") + (command + maybe-string + "The command the user is allowed to run. The default is all commands. +It's preferable to have commands specifieds by absolute paths. If a relative +path is specified, only a restricted PATH will be searched.") + (args + maybe-list-of-strings + "Arguments to command. The command arguments provided by the user need to +match those specified. The keyword args alone means that command must be run +without arguments.") + (setenv + maybe-assoc-list + "Set the specified variables. Variables may also be removed by setting them +to #f, or simply exported, by setting them to #t. If the first character of the +value is ‘$’ then the value to be set is taken from the existing environment +variable with the given name.")) +(define-syntax-rule (permit entry ...) + (permit-statement entry ...)) + +(define (unset? val) + "Tests if VAL is unset." + (equal? val (@@ (gnu services configuration) + %unset-value))) + +(define* (if-set val #:optional (proc identity)) + "Apply PROC to VAL if VAL is not unset, otherwise returns #f." + (if (not (unset? val)) (proc val) #f)) + +(define serialize-permit-statement + (match-record-lambda + (identity as-user command args setenv keepenv? nopass? nolog? persist?) + (format #f "permit ~:[~;keepenv ~]~ + ~:[~;nopass ~]~ + ~:[~;nolog ~]~ + ~:[~;persist ~]~ + ~@[setenv {~{ ~a~} } ~]~ + ~a~@[ as ~a~]~ + ~@[ cmd ~a~]~ + ~@[ args~{ ~a~}~]~%" + keepenv? + nopass? + nolog? + persist? + (if-set setenv (cut serialize-assoc-list #f <>)) + identity + (if-set as-user) + (if-set command) + (if-set args)))) + +(define-configuration/no-serialization deny-statement + (identity + string + "The username to match. Groups may be specified by prepending a colon ':'.") + (as-user + maybe-string + "The target user the running user is allowed to run the command as. The +default is all users.") + (command + maybe-string + "The command the user is allowed to run. The default is all commands. +It's preferable to have commands specifieds by absolute paths. If a relative +path is specified, only a restricted PATH will be searched.") + (args + maybe-string + "Arguments to command. The command arguments provided by the user need to +match those specified. The keyword args alone means that command must be run +without arguments.")) +(define-syntax-rule (deny entry ...) + (deny-statement entry ...)) + +(define serialize-deny-statement + (match-record-lambda + (identity as-user command args) + (format #f "deny ~a~@[ as ~a~]~@[ cmd ~a~]~@[ args~{ ~a~}~]~%" + identity + (if-set as-user) + (if-set command) + (if-set args)))) + +(define (doas-config-file config) + (plain-file "doas.conf" + (apply string-append + (map (lambda (s) + (cond ((permit-statement? s) + (serialize-permit-statement s)) + ((deny-statement? s) + (serialize-deny-statement s)))) + config)))) + +(define (doas-etc-service config) + `(("doas.conf" ,(doas-config-file config)))) + +(define doas-service-type + (service-type (name 'doas-service) + (extensions + (list (service-extension + etc-service-type + doas-etc-service))) + (compose (compose concatenate reverse)) + (extend append) + (default-value '()) + (description "Set /etc/doas.conf"))) + ;;; admin.scm ends here -- 2.41.0