~ruther/guix-local

9bea87a542d52bcaedfb4febb01bbe94b69934cf — Ludovic Courtès 11 years ago a231ef7
activation: Remove undeclared user accounts and groups.

Fixes <http://bugs.gnu.org/19795>.
Reported by David Thompson <dthompson2@worcester.edu>.

* gnu/build/activation.scm (enumerate, current-users, current-groups,
  delete-user, delete-group): New procedures.
  (activate-users+groups): Add calls to 'delete-user' and
  'delete-group'.
* doc/guix.texi (User Accounts): Add a paragraph about statelessness.
  Explain that passwords are preserved.
2 files changed, 60 insertions(+), 5 deletions(-)

M doc/guix.texi
M gnu/build/activation.scm
M doc/guix.texi => doc/guix.texi +14 -2
@@ 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
@code{operating-system} declaration.  They are specified with the
@code{user-account} and @code{user-group} forms:

@example
(user-account


@@ 4252,6 4254,14 @@ User accounts are specified with the @code{user-account} form:
  (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
@command{passwd} are of course preserved across reboot and
reconfiguration.

If you @emph{do} want to have a preset password for an account, then
this field must contain the encrypted password, as a string.

M gnu/build/activation.scm => gnu/build/activation.scm +46 -3
@@ 1,5 1,5 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
;;;
;;; 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."
                ,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 shell password system?
                      (supplementary-groups '())


@@ 186,8 215,22 @@ numeric gid or #f."
                           #:system? system?))))
            groups)

  ;; 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