~ruther/guix-local

58f430f69e71f95cedab9912c1c9f2cc8660fad9 — Giacomo Leidi 2 years ago 478b9cc
accounts: Add /etc/subuid and /etc/subgid support.

This commit adds a new record type, <subid-entry> and serializers
and deserializers for it in (gnu build accounts).  Each instance of this
record represents one line in either /etc/subuid or /etc/subgid.  Since
Shadow uses the same representation for both files, it should be ok if
we do it as well.

This commit adds also <subid-range>, a user facing representation of
<subid-entry>. It is supposed to be usable directly in OS configurations.

* gnu/build/accounts.scm (subid-entry): New record;
(write-subgid): add serializer for subgids;
(write-subuid): add serializer for subuids;
(read-subgid): add serializer for subgids;
(read-subuid): add serializer for subuids.
* gnu/system/accounts.scm (subid-range): New record.
* test/accounts.scm: Test them.

Change-Id: I6b037e40e354c069bf556412bb5b626bd3ea1b2c
Signed-off-by: Giacomo Leidi <goodoldpaul@autistici.org>
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
3 files changed, 106 insertions(+), 3 deletions(-)

M gnu/build/accounts.scm
M gnu/system/accounts.scm
M tests/accounts.scm
M gnu/build/accounts.scm => gnu/build/accounts.scm +34 -3
@@ 1,5 1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019, 2021, 2023 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.org>
;;;
;;; This file is part of GNU Guix.
;;;


@@ 51,13 52,23 @@
            group-entry-gid
            group-entry-members

            subid-entry
            subid-entry?
            subid-entry-name
            subid-entry-start
            subid-entry-count

            %password-lock-file
            write-group
            write-passwd
            write-shadow
            write-subgid
            write-subuid
            read-group
            read-passwd
            read-shadow
            read-subgid
            read-subuid

            %id-min
            %id-max


@@ 68,11 79,12 @@

;;; Commentary:
;;;
;;; This modules provides functionality equivalent to the C library's
;;; This module provides functionality equivalent to the C library's
;;; <shadow.h>, <pwd.h>, and <grp.h> routines, as well as a subset of the
;;; functionality of the Shadow command-line tools.  It can parse and write
;;; /etc/passwd, /etc/shadow, and /etc/group.  It can also take care of UID
;;; and GID allocation in a way similar to what 'useradd' does.
;;; /etc/passwd, /etc/shadow, /etc/group, /etc/subuid and /etc/subgid.  It can
;;; also take care of UID and GID allocation in a way similar to what 'useradd'
;;; does.  The same goes for sub UID and sub GID allocation.
;;;
;;; The benefit is twofold: less code is involved, and the ID allocation
;;; strategy and state preservation is made explicit.


@@ 225,6 237,17 @@ each field."
                   (serialization list->comma-separated comma-separated->list)
                   (default '())))

(define-database-entry <subid-entry>              ;<subid.h>
  subid-entry make-subid-entry
  subid-entry?
  (serialization #\: subid-entry->string string->subid-entry)

  (name            subid-entry-name)
  (start           subid-entry-start
                   (serialization number->string string->number))
  (count           subid-entry-count
                   (serialization number->string string->number)))

(define %password-lock-file
  ;; The password database lock file used by libc's 'lckpwdf'.  Users should
  ;; grab this lock with 'with-file-lock' when they access the databases.


@@ 265,6 288,10 @@ to it atomically and set the appropriate permissions."
  (database-writer "/etc/shadow" #o600 shadow-entry->string))
(define write-group
  (database-writer "/etc/group" #o644 group-entry->string))
(define write-subuid
  (database-writer "/etc/subuid" #o644 subid-entry->string))
(define write-subgid
  (database-writer "/etc/subgid" #o644 subid-entry->string))

(define (database-reader file string->entry)
  (lambda* (#:optional (file-or-port file))


@@ 287,6 314,10 @@ to it atomically and set the appropriate permissions."
  (database-reader "/etc/shadow" string->shadow-entry))
(define read-group
  (database-reader "/etc/group" string->group-entry))
(define read-subuid
  (database-reader "/etc/subuid" string->subid-entry))
(define read-subgid
  (database-reader "/etc/subgid" string->subid-entry))


;;;

M gnu/system/accounts.scm => gnu/system/accounts.scm +17 -0
@@ 1,5 1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.org>
;;;
;;; This file is part of GNU Guix.
;;;


@@ 39,6 40,12 @@
            user-group-id
            user-group-system?

            subid-range
            subid-range?
            subid-range-name
            subid-range-start
            subid-range-count

            sexp->user-account
            sexp->user-group



@@ 85,6 92,16 @@
  (system?        user-group-system?              ; Boolean
                  (default #f)))

(define-record-type* <subid-range>
  subid-range make-subid-range
  subid-range?
  (name           subid-range-name)
  (start          subid-range-start (default #f))    ; number
  (count          subid-range-count                  ; number
                  ; from find_new_sub_gids.c and
                  ; find_new_sub_uids.c
                  (default 65536)))

(define (default-home-directory account)
  "Return the default home directory for ACCOUNT."
  (string-append "/home/" (user-account-name account)))

M tests/accounts.scm => tests/accounts.scm +55 -0
@@ 1,5 1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2024 Giacomo Leidi <goodoldpaul@autistici.org>
;;;
;;; This file is part of GNU Guix.
;;;


@@ 41,6 42,16 @@ root:" (crypt "secret" "$6$abc") ":17169::::::
charlie:" (crypt "hey!" "$6$abc") ":17169::::::
nobody:!:0::::::\n"))

(define %subuid-sample
  "\
root:100000:300
ada:100300:300\n")

(define %subgid-sample
  "\
root:100000:600
ada:100600:300\n")


(test-begin "accounts")



@@ 135,6 146,50 @@ nobody:!:0::::::\n"))
                      read-shadow)
                    port))))

(test-equal "write-subuid"
  %subuid-sample
  (call-with-output-string
    (lambda (port)
      (write-subuid (list (subid-entry
                           (name "root")
                           (start 100000)
                           (count 300))
                          (subid-entry
                           (name "ada")
                           (start 100300)
                           (count 300)))
                    port))))

(test-equal "read-subuid + write-subuid"
  %subuid-sample
  (call-with-output-string
    (lambda (port)
      (write-subuid (call-with-input-string %subuid-sample
                      read-subuid)
                    port))))

(test-equal "write-subgid"
  %subgid-sample
  (call-with-output-string
    (lambda (port)
      (write-subgid (list (subid-entry
                           (name "root")
                           (start 100000)
                           (count 600))
                          (subid-entry
                           (name "ada")
                           (start 100600)
                           (count 300)))
                    port))))

(test-equal "read-subgid + write-subgid"
  %subgid-sample
  (call-with-output-string
    (lambda (port)
      (write-subgid (call-with-input-string %subgid-sample
                      read-subgid)
                    port))))


(define allocate-groups (@@ (gnu build accounts) allocate-groups))
(define allocate-passwd (@@ (gnu build accounts) allocate-passwd))