summary refs log tree commit diff
path: root/gnu
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2014-05-11 22:41:01 +0200
committerLudovic Courtès <ludo@gnu.org>2014-05-11 22:41:58 +0200
commitab6a279abbfa39b1e1bec0e363744d241972f844 (patch)
tree658055e4ecf33226094c9b506251d0715827203b /gnu
parent057d6ce5e42d813b9d5e49ddae5d88e6581cc1d8 (diff)
downloadguix-ab6a279abbfa39b1e1bec0e363744d241972f844.tar.gz
system: Make accounts and groups at activation time.
* gnu/services/base.scm (guix-build-accounts): Remove #:gid parameter;
  add #:group.  Remove 'password' and 'gid' fields in 'user-account'
  form, and add 'group'.
  (guix-service): Remove #:build-user-gid parameter.  Remove 'id' field
  in 'user-group' form.
* gnu/system.scm (etc-directory): Remove #:groups and #:accounts.  No
  longer produce files "passwd", "shadow", and "group".  Adjust caller
  accordingly.
  (%root-account): New variable.
  (operating-system-accounts): Add 'users' variable.  Add %ROOT-ACCOUNT
  only of 'operating-system-users' doesn't already contain a root
  account.
  (user-group->gexp, user-account->gexp): New procedures.
  (operating-system-boot-script): Add calls to 'setenv' and
  'activate-users+groups' in gexp.
* gnu/system/linux.scm (base-pam-services): Add PAM services for
  "user{add,del,mode}" and "group{add,del,mod}".
* gnu/system/shadow.scm (<user-account>)[gid]: Rename to...
  [group]: ... this.
  [supplementary-groups]: New field.
  [uid, password]: Default to #f.
  (<user-group>)[id]: Default to #f.
  (group-file, passwd-file): Remove.
* gnu/system/vm.scm (operating-system-default-contents)[user-directories]:
  Remove.  Add "/home" to the directives.
* guix/build/activation.scm (add-group, add-user,
  activate-users+groups): New procedures.
Diffstat (limited to 'gnu')
-rw-r--r--gnu/services/base.scm10
-rw-r--r--gnu/system.scm95
-rw-r--r--gnu/system/linux.scm14
-rw-r--r--gnu/system/shadow.scm61
-rw-r--r--gnu/system/vm.scm15
5 files changed, 88 insertions, 107 deletions
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 6431a3aaba..1f5ff3e4cb 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -237,8 +237,8 @@ stopped before 'kill' is called."
       (stop #~(make-kill-destructor))))))
 
 (define* (guix-build-accounts count #:key
+                              (group "guixbuild")
                               (first-uid 30001)
-                              (gid 30000)
                               (shadow shadow))
   "Return a list of COUNT user accounts for Guix build users, with UIDs
 starting at FIRST-UID, and under GID."
@@ -247,9 +247,8 @@ starting at FIRST-UID, and under GID."
                     (lambda (n)
                       (user-account
                        (name (format #f "guixbuilder~2,'0d" n))
-                       (password "!")
                        (uid (+ first-uid n -1))
-                       (gid gid)
+                       (group group)
                        (comment (format #f "Guix Build User ~2d" n))
                        (home-directory "/var/empty")
                        (shell #~(string-append #$shadow "/sbin/nologin"))))
@@ -257,11 +256,11 @@ starting at FIRST-UID, and under GID."
                     1))))
 
 (define* (guix-service #:key (guix guix) (builder-group "guixbuild")
-                       (build-user-gid 30000) (build-accounts 10))
+                       (build-accounts 10))
   "Return a service that runs the build daemon from GUIX, and has
 BUILD-ACCOUNTS user accounts available under BUILD-USER-GID."
   (mlet %store-monad ((accounts (guix-build-accounts build-accounts
-                                                     #:gid build-user-gid)))
+                                                     #:group builder-group)))
     (return (service
              (provision '(guix-daemon))
              (requirement '(user-processes))
@@ -274,7 +273,6 @@ BUILD-ACCOUNTS user accounts available under BUILD-USER-GID."
              (user-accounts accounts)
              (user-groups (list (user-group
                                  (name builder-group)
-                                 (id build-user-gid)
                                  (members (map user-account-name
                                                user-accounts)))))))))
 
diff --git a/gnu/system.scm b/gnu/system.scm
index d76c3670f0..bd69532a89 100644
--- a/gnu/system.scm
+++ b/gnu/system.scm
@@ -224,17 +224,12 @@ explicitly appear in OS."
 
 (define* (etc-directory #:key
                         (locale "C") (timezone "Europe/Paris")
-                        (accounts '())
-                        (groups '())
                         (pam-services '())
                         (profile "/var/run/current-system/profile")
                         (sudoers ""))
   "Return a derivation that builds the static part of the /etc directory."
   (mlet* %store-monad
-      ((passwd     (passwd-file accounts))
-       (shadow     (passwd-file accounts #:shadow? #t))
-       (group      (group-file groups))
-       (pam.d      (pam-services->directory pam-services))
+      ((pam.d      (pam-services->directory pam-services))
        (sudoers    (text-file "sudoers" sudoers))
        (login.defs (text-file "login.defs" "# Empty for now.\n"))
        (shells     (text-file "shells"            ; used by xterm and others
@@ -278,10 +273,6 @@ alias ll='ls -l'
                   ("profile" ,#~#$bashrc)
                   ("localtime" ,#~(string-append #$tzdata "/share/zoneinfo/"
                                                  #$timezone))
-                  ("passwd" ,#~#$passwd)
-                  ("shadow" ,#~#$shadow)
-                  ("group" ,#~#$group)
-
                   ("sudoers" ,#~#$sudoers)))))
 
 (define (operating-system-profile os)
@@ -290,18 +281,28 @@ alias ll='ls -l'
   (union (operating-system-packages os)
          #:name "default-profile"))
 
+(define %root-account
+  ;; Default root account.
+  (user-account
+   (name "root")
+   (password "")
+   (uid 0) (group "root")
+   (comment "System administrator")
+   (home-directory "/root")))
+
 (define (operating-system-accounts os)
   "Return the user accounts for OS, including an obligatory 'root' account."
+  (define users
+    ;; Make sure there's a root account.
+    (if (find (lambda (user)
+                (and=> (user-account-uid user) zero?))
+              (operating-system-users os))
+        (operating-system-users os)
+        (cons %root-account (operating-system-users os))))
+
   (mlet %store-monad ((services (operating-system-services os)))
-    (return (cons (user-account
-                   (name "root")
-                   (password "")
-                   (uid 0) (gid 0)
-                   (comment "System administrator")
-                   (home-directory "/root"))
-                  (append (operating-system-users os)
-                          (append-map service-user-accounts
-                                      services))))))
+    (return (append users
+                    (append-map service-user-accounts services)))))
 
 (define (operating-system-etc-directory os)
   "Return that static part of the /etc directory of OS."
@@ -312,12 +313,8 @@ alias ll='ls -l'
                      (delete-duplicates
                       (append (operating-system-pam-services os)
                               (append-map service-pam-services services))))
-       (accounts    (operating-system-accounts os))
-       (profile-drv (operating-system-profile os))
-       (groups   -> (append (operating-system-groups os)
-                            (append-map service-user-groups services))))
-   (etc-directory #:accounts accounts #:groups groups
-                  #:pam-services pam-services
+       (profile-drv (operating-system-profile os)))
+   (etc-directory #:pam-services pam-services
                   #:locale (operating-system-locale os)
                   #:timezone (operating-system-timezone os)
                   #:sudoers (operating-system-sudoers os)
@@ -339,6 +336,25 @@ alias ll='ls -l'
   "root ALL=(ALL) ALL
 %wheel ALL=(ALL) ALL\n")
 
+(define (user-group->gexp group)
+  "Turn GROUP, a <user-group> object, into a list-valued gexp suitable for
+'active-groups'."
+  #~(list #$(user-group-name group)
+          #$(user-group-password group)
+          #$(user-group-id group)))
+
+(define (user-account->gexp account)
+  "Turn ACCOUNT, a <user-account> object, into a list-valued gexp suitable for
+'activate-users'."
+  #~`(#$(user-account-name account)
+      #$(user-account-uid account)
+      #$(user-account-group account)
+      #$(user-account-supplementary-groups account)
+      #$(user-account-comment account)
+      #$(user-account-home-directory account)
+      ,#$(user-account-shell account)             ; this one is a gexp
+      #$(user-account-password account)))
+
 (define (operating-system-boot-script os)
   "Return the boot script for OS---i.e., the code started by the initrd once
 we're running in the final root."
@@ -346,15 +362,25 @@ we're running in the final root."
     '((guix build activation)
       (guix build utils)))
 
-  (mlet* %store-monad
-      ((services (operating-system-services os))
-       (etc      (operating-system-etc-directory os))
-       (modules  (imported-modules %modules))
-       (compiled (compiled-modules %modules))
-       (dmd-conf (dmd-configuration-file services)))
+  (mlet* %store-monad ((services (operating-system-services os))
+                       (etc      (operating-system-etc-directory os))
+                       (modules  (imported-modules %modules))
+                       (compiled (compiled-modules %modules))
+                       (dmd-conf (dmd-configuration-file services))
+                       (accounts (operating-system-accounts os)))
     (define setuid-progs
       (operating-system-setuid-programs os))
 
+    (define user-specs
+      (map user-account->gexp accounts))
+
+    (define groups
+      (append (operating-system-groups os)
+              (append-map service-user-groups services)))
+
+    (define group-specs
+      (map user-group->gexp groups))
+
     (gexp->file "boot"
                 #~(begin
                     (eval-when (expand load eval)
@@ -368,6 +394,13 @@ we're running in the final root."
                     ;; Populate /etc.
                     (activate-etc #$etc)
 
+                    ;; Add users and user groups.
+                    (setenv "PATH"
+                            (string-append #$(@ (gnu packages admin) shadow)
+                                           "/sbin"))
+                    (activate-users+groups (list #$@user-specs)
+                                           (list #$@group-specs))
+
                     ;; Activate setuid programs.
                     (activate-setuid-programs (list #$@setuid-progs))
 
diff --git a/gnu/system/linux.scm b/gnu/system/linux.scm
index 3a43eb45e3..5440f5852f 100644
--- a/gnu/system/linux.scm
+++ b/gnu/system/linux.scm
@@ -154,11 +154,13 @@ should be the name of a file used as the message-of-the-day."
 
 (define* (base-pam-services #:key allow-empty-passwords?)
   "Return the list of basic PAM services everyone would want."
-  (list %pam-other-services
-        (unix-pam-service "su" #:allow-empty-passwords? allow-empty-passwords?)
-        (unix-pam-service "passwd"
-                          #:allow-empty-passwords? allow-empty-passwords?)
-        (unix-pam-service "sudo"
-                          #:allow-empty-passwords? allow-empty-passwords?)))
+  (cons %pam-other-services
+        (map (cut unix-pam-service <>
+                  #:allow-empty-passwords? allow-empty-passwords?)
+             '("su" "passwd" "sudo"
+               "useradd" "userdel" "usermod"
+               "groupadd" "groupdel" "groupmod"
+               ;; TODO: Add other Shadow programs?
+               ))))
 
 ;;; linux.scm ends here
diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm
index 52242ee4e0..8745ddb876 100644
--- a/gnu/system/shadow.scm
+++ b/gnu/system/shadow.scm
@@ -30,9 +30,10 @@
   #:export (user-account
             user-account?
             user-account-name
-            user-account-pass
+            user-account-password
             user-account-uid
-            user-account-gid
+            user-account-group
+            user-account-supplementary-groups
             user-account-comment
             user-account-home-directory
             user-account-shell
@@ -42,11 +43,7 @@
             user-group-name
             user-group-password
             user-group-id
-            user-group-members
-
-            passwd-file
-            group-file
-            guix-build-accounts))
+            user-group-members))
 
 ;;; Commentary:
 ;;;
@@ -58,9 +55,11 @@
   user-account make-user-account
   user-account?
   (name           user-account-name)
-  (password       user-account-pass (default ""))
-  (uid            user-account-uid)
-  (gid            user-account-gid)
+  (password       user-account-password (default #f))
+  (uid            user-account-uid (default #f))
+  (group          user-account-group)             ; number | string
+  (supplementary-groups user-account-supplementary-groups
+                        (default '()))            ; list of strings
   (comment        user-account-comment (default ""))
   (home-directory user-account-home-directory)
   (shell          user-account-shell              ; gexp
@@ -71,47 +70,7 @@
   user-group?
   (name           user-group-name)
   (password       user-group-password (default #f))
-  (id             user-group-id)
+  (id             user-group-id (default #f))
   (members        user-group-members (default '())))
 
-(define (group-file groups)
-  "Return a /etc/group file for GROUPS, a list of <user-group> objects."
-  (define contents
-    (let loop ((groups groups)
-               (result '()))
-      (match groups
-        ((($ <user-group> name _ gid (users ...)) rest ...)
-         ;; XXX: Ignore the group password.
-         (loop rest
-               (cons (string-append name "::" (number->string gid)
-                                    ":" (string-join users ","))
-                     result)))
-        (()
-         (string-join (reverse result) "\n" 'suffix)))))
-
-  (text-file "group" contents))
-
-(define* (passwd-file accounts #:key shadow?)
-  "Return a password file for ACCOUNTS, a list of <user-account> objects.  If
-SHADOW? is true, then it is a /etc/shadow file, otherwise it is a /etc/passwd
-file."
-  ;; XXX: The resulting file is world-readable, so beware when SHADOW? is #t!
-  (define account-exp
-    (match-lambda
-     (($ <user-account> name pass uid gid comment home-dir shell)
-      (if shadow?                                 ; XXX: use (crypt PASS …)?
-          #~(format #t "~a::::::::~%" #$name)
-          #~(format #t "~a:x:~a:~a:~a:~a:~a~%"
-                    #$name #$(number->string uid) #$(number->string gid)
-                    #$comment #$home-dir #$shell)))))
-
-  (define builder
-    #~(begin
-        (with-output-to-file #$output
-          (lambda ()
-            #$@(map account-exp accounts)
-            #t))))
-
-  (gexp->derivation (if shadow? "shadow" "passwd") builder))
-
 ;;; shadow.scm ends here
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 2520853205..ede7ea7726 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -267,16 +267,6 @@ such as /etc files."
 (define (operating-system-default-contents os)
   "Return a list of directives suitable for 'system-qemu-image' describing the
 basic contents of the root file system of OS."
-  (define (user-directories user)
-    (let ((home (user-account-home-directory user))
-          ;; XXX: Deal with automatically allocated ids.
-          (uid  (or (user-account-uid user) 0))
-          (gid  (or (user-account-gid user) 0))
-          (root (string-append "/var/guix/profiles/per-user/"
-                               (user-account-name user))))
-      #~((directory #$root #$uid #$gid)
-         (directory #$home #$uid #$gid))))
-
   (mlet* %store-monad ((os-drv    (operating-system-derivation os))
                        (build-gid (operating-system-build-gid os))
                        (profile   (operating-system-profile os)))
@@ -293,9 +283,8 @@ basic contents of the root file system of OS."
                (directory "/tmp")
                (directory "/var/guix/profiles/per-user/root" 0 0)
 
-               (directory "/root" 0 0)             ; an exception
-               #$@(append-map user-directories
-                              (operating-system-users os))))))
+               (directory "/root" 0 0)            ; an exception
+               (directory "/home" 0 0)))))
 
 (define* (system-qemu-image os
                             #:key