activation: Build account databases with (gnu build accounts).
* 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.
This commit is contained in:
parent
ec600e4544
commit
0ae735bcc8
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
(define-module (gnu build activation)
|
(define-module (gnu build activation)
|
||||||
#:use-module (gnu system accounts)
|
#:use-module (gnu system accounts)
|
||||||
|
#:use-module (gnu build accounts)
|
||||||
#:use-module (gnu build linux-boot)
|
#:use-module (gnu build linux-boot)
|
||||||
#:use-module (guix build utils)
|
#:use-module (guix build utils)
|
||||||
#:use-module (ice-9 ftw)
|
#:use-module (ice-9 ftw)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-11)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
#:export (activate-users+groups
|
#:export (activate-users+groups
|
||||||
activate-user-home
|
activate-user-home
|
||||||
|
@ -43,35 +45,6 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; 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
|
(define %skeleton-directory
|
||||||
;; Directory containing skeleton files for new accounts.
|
;; Directory containing skeleton files for new accounts.
|
||||||
;; Note: keep the trailing '/' so that 'scandir' enters it.
|
;; Note: keep the trailing '/' so that 'scandir' enters it.
|
||||||
|
@ -117,172 +90,32 @@ owner-writable in HOME."
|
||||||
(make-file-writable target))))
|
(make-file-writable target))))
|
||||||
files)))
|
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)
|
(define (activate-users+groups users groups)
|
||||||
"Make sure USERS (a list of user account records) and GROUPS (a list of user
|
"Make sure USERS (a list of user account records) and GROUPS (a list of user
|
||||||
group records) are all available."
|
group records) are all available."
|
||||||
(define (touch file)
|
(define (make-home-directory user)
|
||||||
(close-port (open-file file "a0b")))
|
(let ((home (user-account-home-directory user))
|
||||||
|
(pwd (getpwnam (user-account-name user))))
|
||||||
(define activate-user
|
(mkdir-p home)
|
||||||
(lambda (user)
|
(chown home (passwd:uid pwd) (passwd:gid pwd))
|
||||||
(let ((name (user-account-name user))
|
(chmod home #o700)))
|
||||||
(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")
|
|
||||||
|
|
||||||
;; Allow home directories to be created under /var/lib.
|
;; Allow home directories to be created under /var/lib.
|
||||||
(mkdir-p "/var/lib")
|
(mkdir-p "/var/lib")
|
||||||
|
|
||||||
;; Create the root account so we can use 'useradd' and 'groupadd'.
|
(let-values (((groups passwd shadow)
|
||||||
(activate-user (find (compose zero? user-account-uid) users))
|
(user+group-databases users groups)))
|
||||||
|
(write-group groups)
|
||||||
|
(write-passwd passwd)
|
||||||
|
(write-shadow shadow)
|
||||||
|
|
||||||
;; Then create the groups.
|
;; Home directories of non-system accounts are created by
|
||||||
(for-each (lambda (group)
|
;; 'activate-user-home'.
|
||||||
(let ((name (user-group-name group))
|
(for-each make-home-directory
|
||||||
(password (user-group-password group))
|
(filter (lambda (user)
|
||||||
(gid (user-group-id group))
|
(and (user-account-system? user)
|
||||||
(system? (user-group-system? group)))
|
(user-account-create-home-directory? user)))
|
||||||
(unless (false-if-exception (getgrnam name))
|
users))))
|
||||||
(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))))
|
|
||||||
|
|
||||||
(define (activate-user-home users)
|
(define (activate-user-home users)
|
||||||
"Create and populate the home directory of USERS, a list of tuples, unless
|
"Create and populate the home directory of USERS, a list of tuples, unless
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
|
;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
|
@ -117,7 +117,6 @@ STORE."
|
||||||
(directory "/var/tmp" 0 0 #o1777)
|
(directory "/var/tmp" 0 0 #o1777)
|
||||||
(directory "/var/lock" 0 0 #o1777)
|
(directory "/var/lock" 0 0 #o1777)
|
||||||
|
|
||||||
(directory "/root" 0 0) ; an exception
|
|
||||||
(directory "/home" 0 0)))
|
(directory "/home" 0 0)))
|
||||||
|
|
||||||
(define (populate-root-file-system system target)
|
(define (populate-root-file-system system target)
|
||||||
|
|
|
@ -302,8 +302,6 @@ group."
|
||||||
#~(begin
|
#~(begin
|
||||||
(use-modules (gnu system accounts))
|
(use-modules (gnu system accounts))
|
||||||
|
|
||||||
(setenv "PATH"
|
|
||||||
(string-append #$(@ (gnu packages admin) shadow) "/sbin"))
|
|
||||||
(activate-users+groups (map sexp->user-account (list #$@user-specs))
|
(activate-users+groups (map sexp->user-account (list #$@user-specs))
|
||||||
(map sexp->user-group (list #$@group-specs))))))
|
(map sexp->user-group (list #$@group-specs))))))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue