[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

01/02: activation: Remove undeclared user accounts and groups.

From: Ludovic Courtès
Subject: 01/02: activation: Remove undeclared user accounts and groups.
Date: Wed, 08 Apr 2015 19:41:12 +0000

civodul pushed a commit to branch master
in repository guix.

commit 9bea87a542d52bcaedfb4febb01bbe94b69934cf
Author: Ludovic Courtès <address@hidden>
Date:   Wed Apr 8 21:23:45 2015 +0200

    activation: Remove undeclared user accounts and groups.
    Fixes <>.
    Reported by David Thompson <address@hidden>.
    * gnu/build/activation.scm (enumerate, current-users, current-groups,
      delete-user, delete-group): New procedures.
      (activate-users+groups): Add calls to 'delete-user' and
    * doc/guix.texi (User Accounts): Add a paragraph about statelessness.
      Explain that passwords are preserved.
 doc/guix.texi            |   16 +++++++++++++-
 gnu/build/activation.scm |   49 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 70604b7..c0af4cb 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -4238,7 +4238,9 @@ command, from the same-named package.  This relies on the
 @node User Accounts
 @subsection User Accounts
-User accounts are specified with the @code{user-account} form:
+User accounts and groups are entirely managed through the
address@hidden declaration.  They are specified with the
address@hidden and @code{user-group} forms:
@@ -4252,6 +4254,14 @@ User accounts are specified with the @code{user-account} 
   (home-directory "/home/alice"))
 @end example
+When booting or upon completion of @command{guix system reconfigure},
+the system ensures that only the user accounts and groups specified in
+the @code{operating-system} declaration exist, and with the specified
+properties.  Thus, account or group creations or modifications made by
+directly invoking commands such as @command{useradd} are lost upon
+reconfiguration or reboot.  This ensures that the system remains exactly
+as declared.
 @deftp {Data Type} user-account
 Objects of this type represent user accounts.  The following members may
 be specified:
@@ -4291,7 +4301,9 @@ graphical login managers do not list them.
 @item @code{password} (default: @code{#f})
 You would normally leave this field to @code{#f}, initialize user
 passwords as @code{root} with the @command{passwd} command, and then let
-users change it with @command{passwd}.
+users change it with @command{passwd}.  Passwords set with
address@hidden are of course preserved across reboot and
 If you @emph{do} want to have a preset password for an account, then
 this field must contain the encrypted password, as a string.
diff --git a/gnu/build/activation.scm b/gnu/build/activation.scm
index 909e971..64c3410 100644
--- a/gnu/build/activation.scm
+++ b/gnu/build/activation.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014 Ludovic Courtès <address@hidden>
+;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <address@hidden>
 ;;; Copyright © 2015 Mark H Weaver <address@hidden>
 ;;; This file is part of GNU Guix.
@@ -40,6 +40,24 @@
 ;;; 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."
@@ -128,6 +146,17 @@ properties.  Return #t on success."
     (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 shell password system?
                       (supplementary-groups '())
@@ -186,8 +215,22 @@ numeric gid or #f."
                            #:system? system?))))
-  ;; Finally create the other user accounts.
-  (for-each activate-user users))
+  ;; 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))
+                             (match users
+                               (((names . _) ...)
+                                names))))
+  (for-each delete-group
+            (lset-difference string=?
+                             (map group:name (current-groups))
+                             (match groups
+                               (((names . _) ...)
+                                names)))))
 (define (activate-etc etc)
   "Install ETC, a directory in the store, as the source of static files for

reply via email to

[Prev in Thread] Current Thread [Next in Thread]