From patchwork Mon Mar 4 11:16:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ludovic_Court=C3=A8s?= X-Patchwork-Id: 1287 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 DB5FA16CF6; Mon, 4 Mar 2019 11:17:27 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTP id 3E6CB16C43 for ; Mon, 4 Mar 2019 11:17:27 +0000 (GMT) Received: from localhost ([127.0.0.1]:52096 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h0lb4-0002Pf-Ra for patchwork@mira.cbaines.net; Mon, 04 Mar 2019 06:17:26 -0500 Received: from eggs.gnu.org ([209.51.188.92]:36276) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h0lao-0002Jh-99 for guix-patches@gnu.org; Mon, 04 Mar 2019 06:17:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h0lah-0000Yn-Iy for guix-patches@gnu.org; Mon, 04 Mar 2019 06:17:10 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45488) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h0lah-0000Y7-ET for guix-patches@gnu.org; Mon, 04 Mar 2019 06:17:03 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1h0lah-0006HP-9J for guix-patches@gnu.org; Mon, 04 Mar 2019 06:17:03 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#34730] [PATCH 4/4] activation: Build account databases with (gnu build accounts). Resent-From: Ludovic =?utf-8?q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 04 Mar 2019 11:17:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 34730 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 34730@debbugs.gnu.org Received: via spool by 34730-submit@debbugs.gnu.org id=B34730.155169821924106 (code B ref 34730); Mon, 04 Mar 2019 11:17:03 +0000 Received: (at 34730) by debbugs.gnu.org; 4 Mar 2019 11:16:59 +0000 Received: from localhost ([127.0.0.1]:59028 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1h0lac-0006Gj-Pd for submit@debbugs.gnu.org; Mon, 04 Mar 2019 06:16:59 -0500 Received: from hera.aquilenet.fr ([185.233.100.1]:34618) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1h0laY-0006GD-Fz for 34730@debbugs.gnu.org; Mon, 04 Mar 2019 06:16:55 -0500 Received: from localhost (localhost [127.0.0.1]) by hera.aquilenet.fr (Postfix) with ESMTP id E538A9B04; Mon, 4 Mar 2019 12:16:53 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at aquilenet.fr Received: from hera.aquilenet.fr ([127.0.0.1]) by localhost (hera.aquilenet.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SAkdgvaYT5b5; Mon, 4 Mar 2019 12:16:52 +0100 (CET) Received: from gnu.org (unknown [IPv6:2001:660:6102:320:e120:2c8f:8909:cdfe]) by hera.aquilenet.fr (Postfix) with ESMTPSA id CA86A9B05; Mon, 4 Mar 2019 12:16:50 +0100 (CET) From: Ludovic =?utf-8?q?Court=C3=A8s?= Date: Mon, 4 Mar 2019 12:16:44 +0100 Message-Id: <20190304111644.8573-4-ludo@gnu.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190304111644.8573-1-ludo@gnu.org> References: <20190304111644.8573-1-ludo@gnu.org> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/build/activation.scm (enumerate, current-users, current-groups) (add-group, add-user, modify-user, ensure-user): Remove. (activate-users+groups)[touch, activate-user]: Remove. [make-home-directory]: New procedure. Rewrite in terms of 'user+group-databases', 'write-group', etc. * gnu/build/install.scm (directives): Remove "/root". * gnu/system/shadow.scm (account-activation): Remove (setenv "PATH" ...) expression, which is now unneeded. --- gnu/build/activation.scm | 207 ++++----------------------------------- gnu/build/install.scm | 3 +- gnu/system/shadow.scm | 2 - 3 files changed, 21 insertions(+), 191 deletions(-) diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm index 820e04d648..aa5b7031f1 100644 --- a/gnu/build/activation.scm +++ b/gnu/build/activation.scm @@ -19,11 +19,13 @@ (define-module (gnu build activation) #:use-module (gnu system accounts) + #:use-module (gnu build accounts) #:use-module (gnu build linux-boot) #:use-module (guix build utils) #:use-module (ice-9 ftw) #:use-module (ice-9 match) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-11) #:use-module (srfi srfi-26) #:export (activate-users+groups activate-user-home @@ -43,35 +45,6 @@ ;;; ;;; Code: -(define (enumerate thunk) - "Return the list of values returned by THUNK until it returned #f." - (let loop ((entry (thunk)) - (result '())) - (if (not entry) - (reverse result) - (loop (thunk) (cons entry result))))) - -(define (current-users) - "Return the passwd entries for all the currently defined user accounts." - (setpw) - (enumerate getpwent)) - -(define (current-groups) - "Return the group entries for all the currently defined user groups." - (setgr) - (enumerate getgrent)) - -(define* (add-group name #:key gid password system? - (log-port (current-error-port))) - "Add NAME as a user group, with the given numeric GID if specified." - ;; Use 'groupadd' from the Shadow package. - (format log-port "adding group '~a'...~%" name) - (let ((args `(,@(if gid `("-g" ,(number->string gid)) '()) - ,@(if password `("-p" ,password) '()) - ,@(if system? `("--system") '()) - ,name))) - (zero? (apply system* "groupadd" args)))) - (define %skeleton-directory ;; Directory containing skeleton files for new accounts. ;; Note: keep the trailing '/' so that 'scandir' enters it. @@ -117,172 +90,32 @@ owner-writable in HOME." (make-file-writable target)))) files))) -(define* (add-user name group - #:key uid comment home create-home? - shell password system? - (supplementary-groups '()) - (log-port (current-error-port))) - "Create an account for user NAME part of GROUP, with the specified -properties. Return #t on success." - (format log-port "adding user '~a'...~%" name) - - (if (and uid (zero? uid)) - - ;; 'useradd' fails with "Cannot determine your user name" if the root - ;; account doesn't exist. Thus, for bootstrapping purposes, create that - ;; one manually. - (let ((home (or home "/root"))) - (call-with-output-file "/etc/shadow" - (cut format <> "~a::::::::~%" name)) - (call-with-output-file "/etc/passwd" - (cut format <> "~a:x:~a:~a:~a:~a:~a~%" - name "0" "0" comment home shell)) - (chmod "/etc/shadow" #o600) - (copy-account-skeletons home) - (chmod home #o700) - #t) - - ;; Use 'useradd' from the Shadow package. - (let ((args `(,@(if uid `("-u" ,(number->string uid)) '()) - "-g" ,(if (number? group) (number->string group) group) - ,@(if (pair? supplementary-groups) - `("-G" ,(string-join supplementary-groups ",")) - '()) - ,@(if comment `("-c" ,comment) '()) - ,@(if home `("-d" ,home) '()) - - ;; Home directories of non-system accounts are created by - ;; 'activate-user-home'. - ,@(if (and home create-home? system? - (not (file-exists? home))) - '("--create-home") - '()) - - ,@(if shell `("-s" ,shell) '()) - ,@(if password `("-p" ,password) '()) - ,@(if system? '("--system") '()) - ,name))) - (and (zero? (apply system* "useradd" args)) - (begin - ;; Since /etc/skel is a link to a directory in the store where - ;; all files have the writable bit cleared, and since 'useradd' - ;; preserves permissions when it copies them, explicitly make - ;; them writable. - (make-skeletons-writable home) - #t))))) - -(define* (modify-user name group - #:key uid comment home create-home? - shell password system? - (supplementary-groups '()) - (log-port (current-error-port))) - "Modify user account NAME to have all the given settings." - ;; Use 'usermod' from the Shadow package. - (let ((args `(,@(if uid `("-u" ,(number->string uid)) '()) - "-g" ,(if (number? group) (number->string group) group) - ,@(if (pair? supplementary-groups) - `("-G" ,(string-join supplementary-groups ",")) - '()) - ,@(if comment `("-c" ,comment) '()) - ;; Don't use '--move-home'. - ,@(if home `("-d" ,home) '()) - ,@(if shell `("-s" ,shell) '()) - ,name))) - (zero? (apply system* "usermod" args)))) - -(define* (delete-user name #:key (log-port (current-error-port))) - "Remove user account NAME. Return #t on success. This may fail if NAME is -logged in." - (format log-port "deleting user '~a'...~%" name) - (zero? (system* "userdel" name))) - -(define* (delete-group name #:key (log-port (current-error-port))) - "Remove group NAME. Return #t on success." - (format log-port "deleting group '~a'...~%" name) - (zero? (system* "groupdel" name))) - -(define* (ensure-user name group - #:key uid comment home create-home? - shell password system? - (supplementary-groups '()) - (log-port (current-error-port)) - #:rest rest) - "Make sure user NAME exists and has the relevant settings." - (if (false-if-exception (getpwnam name)) - (apply modify-user name group rest) - (apply add-user name group rest))) - (define (activate-users+groups users groups) "Make sure USERS (a list of user account records) and GROUPS (a list of user group records) are all available." - (define (touch file) - (close-port (open-file file "a0b"))) - - (define activate-user - (lambda (user) - (let ((name (user-account-name user)) - (uid (user-account-uid user)) - (group (user-account-group user)) - (supplementary-groups - (user-account-supplementary-groups user)) - (comment (user-account-comment user)) - (home (user-account-home-directory user)) - (create-home? (user-account-create-home-directory? user)) - (shell (user-account-shell user)) - (password (user-account-password user)) - (system? (user-account-system? user))) - (let ((profile-dir (string-append "/var/guix/profiles/per-user/" - name))) - (ensure-user name group - #:uid uid - #:system? system? - #:supplementary-groups supplementary-groups - #:comment comment - #:home home - #:create-home? create-home? - - #:shell shell - #:password password) - - (unless system? - ;; Create the profile directory for the new account. - (let ((pw (getpwnam name))) - (mkdir-p profile-dir) - (chown profile-dir (passwd:uid pw) (passwd:gid pw)))))))) - - ;; 'groupadd' aborts if the file doesn't already exist. - (touch "/etc/group") + (define (make-home-directory user) + (let ((home (user-account-home-directory user)) + (pwd (getpwnam (user-account-name user)))) + (mkdir-p home) + (chown home (passwd:uid pwd) (passwd:gid pwd)) + (chmod home #o700))) ;; Allow home directories to be created under /var/lib. (mkdir-p "/var/lib") - ;; Create the root account so we can use 'useradd' and 'groupadd'. - (activate-user (find (compose zero? user-account-uid) users)) + (let-values (((groups passwd shadow) + (user+group-databases users groups))) + (write-group groups) + (write-passwd passwd) + (write-shadow shadow) - ;; Then create the groups. - (for-each (lambda (group) - (let ((name (user-group-name group)) - (password (user-group-password group)) - (gid (user-group-id group)) - (system? (user-group-system? group))) - (unless (false-if-exception (getgrnam name)) - (add-group name - #:gid gid #:password password - #:system? system?)))) - groups) - - ;; Create the other user accounts. - (for-each activate-user users) - - ;; Finally, delete extra user accounts and groups. - (for-each delete-user - (lset-difference string=? - (map passwd:name (current-users)) - (map user-account-name users))) - (for-each delete-group - (lset-difference string=? - (map group:name (current-groups)) - (map user-group-name groups)))) + ;; Home directories of non-system accounts are created by + ;; 'activate-user-home'. + (for-each make-home-directory + (filter (lambda (user) + (and (user-account-system? user) + (user-account-create-home-directory? user))) + users)))) (define (activate-user-home users) "Create and populate the home directory of USERS, a list of tuples, unless diff --git a/gnu/build/install.scm b/gnu/build/install.scm index c9ebe124fe..c0d4d44091 100644 --- a/gnu/build/install.scm +++ b/gnu/build/install.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès +;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès ;;; Copyright © 2016 Chris Marusich ;;; ;;; This file is part of GNU Guix. @@ -117,7 +117,6 @@ STORE." (directory "/var/tmp" 0 0 #o1777) (directory "/var/lock" 0 0 #o1777) - (directory "/root" 0 0) ; an exception (directory "/home" 0 0))) (define (populate-root-file-system system target) diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm index 4e5b6ae5f2..7dc36f4a45 100644 --- a/gnu/system/shadow.scm +++ b/gnu/system/shadow.scm @@ -302,8 +302,6 @@ group." #~(begin (use-modules (gnu system accounts)) - (setenv "PATH" - (string-append #$(@ (gnu packages admin) shadow) "/sbin")) (activate-users+groups (map sexp->user-account (list #$@user-specs)) (map sexp->user-group (list #$@group-specs))))))