summary refs log tree commit diff
diff options
context:
space:
mode:
authorMathieu Othacehe <m.othacehe@gmail.com>2018-12-07 14:04:25 +0900
committerLudovic Courtès <ludo@gnu.org>2019-01-17 14:04:26 +0100
commitbf304dbceadf89c2722168be97d9673f94608aa6 (patch)
treef9ac12121124e26294f0d9654485a861d316533a
parent71cd8a5870d11dc5f74c7e9b38db03d6cc633794 (diff)
downloadguix-bf304dbceadf89c2722168be97d9673f94608aa6.tar.gz
installer: partionment: Add encryption support.
* gnu/installer.scm (set-installer-path): Add cryptsetup.
* gnu/installer/newt/partition.scm (prompt-luks-passwords): New procedure,
(run-partioning-page): Add the possibility to set encryption to "On" on a
partition and choose a label, add a new partition scheme: "Guided - using the
entire disk with encryption", prompt for encryption passwords before
proceeding to formating.
* gnu/installer/parted.scm (<user-partition>)[crypt-label],
[crypt-password]: New fields,
(partition-description): add the encryption label,
(user-partition-description): add an encryption field,
(auto-partition): add two partitioning schemes: entire-crypted-root and
entire-crypted-root-home,
(call-with-luks-key-file): new procedure,
(user-partition-upper-path): new procedure,
(luks-format-and-open): new procedure,
(luks-close): new procedure,
(format-user-partitions): format and open luks partitions before creating
file-system.
(mount-user-partitions): use the path returned by user-partition-upper-path,
(umount-user-partitions): close the luks partitions,
(user-partition->file-system): set device field to label for luks partitions
and to uuid for the rest,
(user-partition->mapped-device): new procedure,
(user-partitions->configuration): add mapped-devices field.
-rw-r--r--gnu/installer.scm2
-rw-r--r--gnu/installer/newt/partition.scm45
-rw-r--r--gnu/installer/parted.scm202
3 files changed, 195 insertions, 54 deletions
diff --git a/gnu/installer.scm b/gnu/installer.scm
index 2f01d39d1a..fd66359cbe 100644
--- a/gnu/installer.scm
+++ b/gnu/installer.scm
@@ -28,6 +28,7 @@
   #:use-module (gnu packages base)
   #:use-module (gnu packages bash)
   #:use-module (gnu packages connman)
+  #:use-module (gnu packages cryptsetup)
   #:use-module (gnu packages disk)
   #:use-module (gnu packages guile)
   #:autoload   (gnu packages gnupg) (guile-gcrypt)
@@ -272,6 +273,7 @@ selected keymap."
     #~(let* ((inputs
               '#$(append (list bash ;start subshells
                                connman ;call connmanctl
+                               cryptsetup
                                dosfstools ;mkfs.fat
                                e2fsprogs ;mkfs.ext4
                                kbd ;chvt
diff --git a/gnu/installer/newt/partition.scm b/gnu/installer/newt/partition.scm
index 6aa8bfb598..f4d1735dda 100644
--- a/gnu/installer/newt/partition.scm
+++ b/gnu/installer/newt/partition.scm
@@ -138,6 +138,25 @@ an inform the user with an appropriate error-page and return #f."
             #f))
     (can-create-partition? user-partition)))
 
+(define (prompt-luks-passwords user-partitions)
+  "Prompt for the luks passwords of the encrypted partitions in
+USER-PARTITIONS list. Return this list with password fields filled-in."
+  (map (lambda (user-part)
+         (let* ((crypt-label (user-partition-crypt-label user-part))
+                (path (user-partition-path user-part))
+                (password-page
+                 (lambda ()
+                   (run-input-page
+                    (format #f (G_ "Please enter the password for the \
+encryption of partition ~a (label: ~a).") path crypt-label)
+                    (G_ "Password required")))))
+           (if crypt-label
+               (user-partition
+                (inherit user-part)
+                (crypt-password (password-page)))
+               user-part)))
+       user-partitions))
+
 (define* (run-partition-page target-user-partition
                              #:key
                              (default-item #f))
@@ -244,6 +263,18 @@ by USER-PART, if it is applicable for the partition type."
              (mount-point (if new-esp?
                               (default-esp-mount-point)
                               "")))))
+         ((crypt-label)
+          (let* ((label (user-partition-crypt-label
+                         target-user-partition))
+                 (new-label
+                  (and (not label)
+                       (run-input-page
+                        (G_ "Please enter the encrypted label")
+                        (G_ "Encryption label")))))
+            (user-partition
+             (inherit target-user-partition)
+             (need-formating? #t)
+             (crypt-label new-label))))
          ((need-formating?)
           (user-partition
            (inherit target-user-partition)
@@ -668,6 +699,7 @@ by pressing the Exit button.~%~%")))
   (define (run-page devices)
     (let* ((items
             '((entire . "Guided - using the entire disk")
+              (entire-crypted . "Guided - using the entire disk with encryption")
               (manual . "Manual")))
            (result (run-listbox-selection-page
                     #:info-text (G_ "Please select a partitioning method.")
@@ -677,8 +709,9 @@ by pressing the Exit button.~%~%")))
                     #:button-text (G_ "Exit")
                     #:button-callback-procedure button-exit-action))
            (method (car result)))
-      (case method
-        ((entire)
+      (cond
+       ((or (eq? method 'entire)
+            (eq? method 'entire-crypted))
          (let* ((device (run-device-page devices))
                 (disk-type (disk-probe device))
                 (disk (if disk-type
@@ -696,7 +729,7 @@ by pressing the Exit button.~%~%")))
                                    (disk-partitions disk)))))
            (run-disk-page (list disk) user-partitions
                           #:guided? #t)))
-        ((manual)
+       ((eq? method 'manual)
          (let* ((disks (map disk-new devices))
                 (user-partitions (append-map
                                   create-special-user-partitions
@@ -708,11 +741,13 @@ by pressing the Exit button.~%~%")))
   (init-parted)
   (let* ((non-install-devices (non-install-devices))
          (user-partitions (run-page non-install-devices))
+         (user-partitions-with-pass (prompt-luks-passwords
+                                     user-partitions))
          (form (draw-formating-page)))
     ;; Make sure the disks are not in use before proceeding to formating.
     (free-parted non-install-devices)
-    (run-error-page (format #f "~a" user-partitions)
+    (run-error-page (format #f "~a" user-partitions-with-pass)
                     "user-partitions")
-    (format-user-partitions user-partitions)
+    (format-user-partitions user-partitions-with-pass)
     (destroy-form-and-pop form)
     user-partitions))
diff --git a/gnu/installer/parted.scm b/gnu/installer/parted.scm
index b0fe672131..c56da60550 100644
--- a/gnu/installer/parted.scm
+++ b/gnu/installer/parted.scm
@@ -22,13 +22,16 @@
   #:use-module (gnu installer newt page)
   #:use-module (gnu system uuid)
   #:use-module ((gnu build file-systems)
-                #:select (read-partition-uuid))
+                #:select (read-partition-uuid
+                          find-partition-by-luks-uuid))
   #:use-module (guix build syscalls)
   #:use-module (guix build utils)
   #:use-module (guix records)
+  #:use-module (guix utils)
   #:use-module (guix i18n)
   #:use-module (parted)
   #:use-module (ice-9 match)
+  #:use-module (rnrs io ports)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-34)
@@ -41,6 +44,8 @@
             user-partition-type
             user-partition-path
             user-partition-disk-path
+            user-partition-crypt-label
+            user-partition-crypt-password
             user-partition-fs-type
             user-partition-bootable?
             user-partition-esp?
@@ -128,6 +133,10 @@
                         (default #f))
   (disk-path            user-partition-disk-path
                         (default #f))
+  (crypt-label          user-partition-crypt-label
+                        (default #f))
+  (crypt-password       user-partition-crypt-password
+                        (default #f))
   (fs-type              user-partition-fs-type
                         (default 'ext4))
   (bootable?            user-partition-bootable?
@@ -427,7 +436,9 @@ DEVICE."
   (define (maybe-string-pad string length)
     "Returned a string formatted by padding STRING of LENGTH characters to the
 right. If STRING is #f use an empty string."
-    (string-pad-right (or string "") length))
+    (if (and string (not (string=? string "")))
+        (string-pad-right string length)
+        ""))
 
   (let* ((disk (partition-disk partition))
          (device (disk-device disk))
@@ -452,6 +463,8 @@ right. If STRING is #f use an empty string."
          (fs-type (partition-fs-type partition))
          (fs-type-name (and fs-type
                             (filesystem-type-name fs-type)))
+         (crypt-label (and user-partition
+                           (user-partition-crypt-label user-partition)))
          (flags (and (not (freespace-partition? partition))
                      (partition-print-flags partition)))
          (mount-point (and user-partition
@@ -464,6 +477,7 @@ right. If STRING is #f use an empty string."
       ,(or fs-type-name "")
       ,(or flags "")
       ,(or mount-point "")
+      ,(or crypt-label "")
       ,(maybe-string-pad name 30))))
 
 (define (partitions-descriptions partitions user-partitions)
@@ -525,6 +539,7 @@ determined by MAX-LENGTH-COLUMN procedure."
          (bootable? (user-partition-bootable? user-partition))
          (esp? (user-partition-esp? user-partition))
          (need-formating? (user-partition-need-formating? user-partition))
+         (crypt-label (user-partition-crypt-label user-partition))
          (size (user-partition-size user-partition))
          (mount-point (user-partition-mount-point user-partition)))
     `(,@(if has-name?
@@ -555,6 +570,15 @@ determined by MAX-LENGTH-COLUMN procedure."
                                          (partition-length partition)))))
               `((size . ,(string-append "Size : " size-formatted))))
             '())
+      ,@(if (or (eq? type 'extended)
+                (eq? fs-type 'swap))
+            '()
+            `((crypt-label
+               . ,(string-append
+                   "Encryption: "
+                   (if crypt-label
+                       (format #f "Yes (label ~a)" crypt-label)
+                       "No")))))
       ,@(if (or (freespace-partition? partition)
                 (eq? fs-type 'swap))
             '()
@@ -854,7 +878,8 @@ USER-PARTITIONS list and return the updated list."
        user-partitions))
 
 (define* (auto-partition disk
-                         #:key (scheme 'entire-root))
+                         #:key
+                         (scheme 'entire-root))
   "Automatically create partitions on DISK. All the previous
 partitions (except the ESP on a GPT disk, if present) are wiped. SCHEME is the
 desired partitioning scheme. It can be 'entire-root or
@@ -913,46 +938,57 @@ swap partition, a root partition and a home partition."
                       (bios-grub? #t)
                       (size bios-grub-size)))))
            (new-partitions
-            (case scheme
-              ((entire-root)
-               `(,@(if start-partition
-                       `(,start-partition)
-                       '())
-                 ,(user-partition
-                   (fs-type 'swap)
-                   (size swap-size))
-                 ,(user-partition
-                   (fs-type 'ext4)
-                   (bootable? has-extended?)
-                   (size "100%")
-                   (mount-point "/"))))
-              ((entire-root-home)
-               `(,@(if start-partition
-                       `(,start-partition)
-                       '())
-                 ,(user-partition
-                   (fs-type 'ext4)
-                   (bootable? has-extended?)
-                   (size "33%")
-                   (mount-point "/"))
-                 ,@(if has-extended?
-                       `(,(user-partition
-                           (type 'extended)
-                           (size "100%")))
-                       '())
-                 ,(user-partition
-                   (type (if has-extended?
-                             'logical
-                             'normal))
-                   (fs-type 'swap)
-                   (size swap-size))
-                 ,(user-partition
-                   (type (if has-extended?
-                             'logical
-                             'normal))
-                   (fs-type 'ext4)
-                   (size "100%")
-                   (mount-point "/home"))))))
+            (cond
+             ((or (eq? scheme 'entire-root)
+                  (eq? scheme 'entire-crypted-root))
+              (let ((crypted? (eq? scheme 'entire-crypted-root)))
+                `(,@(if start-partition
+                        `(,start-partition)
+                        '())
+                  ,@(if crypted?
+                     '()
+                     `(,(user-partition
+                         (fs-type 'swap)
+                         (size swap-size))))
+                  ,(user-partition
+                    (fs-type 'ext4)
+                    (bootable? has-extended?)
+                    (crypt-label (and crypted? "cryptroot"))
+                    (size "100%")
+                    (mount-point "/")))))
+             ((or (eq? scheme 'entire-root-home)
+                  (eq? scheme 'entire-crypted-root-home))
+              (let ((crypted? (eq? scheme 'entire-crypted-root-home)))
+                `(,@(if start-partition
+                        `(,start-partition)
+                        '())
+                  ,(user-partition
+                    (fs-type 'ext4)
+                    (bootable? has-extended?)
+                    (crypt-label (and crypted? "cryptroot"))
+                    (size "33%")
+                    (mount-point "/"))
+                  ,@(if has-extended?
+                        `(,(user-partition
+                            (type 'extended)
+                            (size "100%")))
+                        '())
+                  ,@(if crypted?
+                        '()
+                        `(,(user-partition
+                            (type (if has-extended?
+                                      'logical
+                                      'normal))
+                            (fs-type 'swap)
+                            (size swap-size))))
+                  ,(user-partition
+                    (type (if has-extended?
+                              'logical
+                              'normal))
+                    (fs-type 'ext4)
+                    (crypt-label (and crypted? "crypthome"))
+                    (size "100%")
+                    (mount-point "/home")))))))
            (new-partitions* (force-user-partitions-formating
                              new-partitions)))
       (create-adjacent-partitions disk
@@ -1013,6 +1049,40 @@ bit bucket."
   (with-null-output-ports
    (invoke "mkswap" "-f" partition)))
 
+(define (call-with-luks-key-file password proc)
+  "Write PASSWORD in a temporary file and pass it to PROC as argument."
+  (call-with-temporary-output-file
+   (lambda (file port)
+     (put-string port password)
+     (close port)
+     (proc file))))
+
+(define (user-partition-upper-path user-partition)
+  "Return the path of the virtual block device corresponding to USER-PARTITION
+if it is encrypted, or the plain path otherwise."
+  (let ((crypt-label (user-partition-crypt-label user-partition))
+        (path (user-partition-path user-partition)))
+    (if crypt-label
+        (string-append "/dev/mapper/" crypt-label)
+        path)))
+
+(define (luks-format-and-open user-partition)
+  "Format and open the crypted partition pointed by USER-PARTITION."
+  (let* ((path (user-partition-path user-partition))
+         (label (user-partition-crypt-label user-partition))
+         (password (user-partition-crypt-password user-partition)))
+    (call-with-luks-key-file
+     password
+     (lambda (key-file)
+       (system* "cryptsetup" "-q" "luksFormat" path key-file)
+       (system* "cryptsetup" "open" "--type" "luks"
+                "--key-file" key-file path label)))))
+
+(define (luks-close user-partition)
+  "Close the crypted partition pointed by USER-PARTITION."
+  (let ((label (user-partition-crypt-label user-partition)))
+    (system* "cryptsetup" "close" label)))
+
 (define (format-user-partitions user-partitions)
   "Format the <user-partition> records in USER-PARTITIONS list with
 NEED-FORMATING? field set to #t."
@@ -1021,8 +1091,12 @@ NEED-FORMATING? field set to #t."
      (let* ((need-formating?
              (user-partition-need-formating? user-partition))
             (type (user-partition-type user-partition))
-            (path (user-partition-path user-partition))
+            (crypt-label (user-partition-crypt-label user-partition))
+            (path (user-partition-upper-path user-partition))
             (fs-type (user-partition-fs-type user-partition)))
+       (when crypt-label
+         (luks-format-and-open user-partition))
+
        (case fs-type
          ((ext4)
           (and need-formating?
@@ -1061,9 +1135,11 @@ respective mount-points."
                                        mount-point))
                        (fs-type
                         (user-partition-fs-type user-partition))
+                       (crypt-label
+                        (user-partition-crypt-label user-partition))
                        (mount-type
                         (user-fs-type->mount-type fs-type))
-                       (path (user-partition-path user-partition)))
+                       (path (user-partition-upper-path user-partition)))
                   (mkdir-p target)
                   (mount path target mount-type)))
               sorted-partitions)))
@@ -1075,10 +1151,14 @@ respective mount-points."
     (for-each (lambda (user-partition)
                 (let* ((mount-point
                         (user-partition-mount-point user-partition))
+                       (crypt-label
+                        (user-partition-crypt-label user-partition))
                        (target
                         (string-append (%installer-target-dir)
                                        mount-point)))
-                  (umount target)))
+                  (umount target)
+                  (when crypt-label
+                    (luks-close user-partition))))
               (reverse sorted-partitions))))
 
 (define (find-swap-user-partitions user-partitions)
@@ -1119,14 +1199,21 @@ the FS-TYPE field set to 'swap, return the empty list if none found."
 (gnu system file-systems) module and return it."
   (let* ((mount-point (user-partition-mount-point user-partition))
          (fs-type (user-partition-fs-type user-partition))
+         (crypt-label (user-partition-crypt-label user-partition))
          (mount-type (user-fs-type->mount-type fs-type))
          (path (user-partition-path user-partition))
+         (upper-path (user-partition-upper-path user-partition))
          (uuid (uuid->string (read-partition-uuid path)
                              fs-type)))
     `(file-system
        (mount-point ,mount-point)
-       (device (uuid ,uuid (quote ,fs-type)))
-       (type ,mount-type))))
+       (device ,@(if crypt-label
+                     `(,upper-path)
+                     `((uuid ,uuid (quote ,fs-type)))))
+       (type ,mount-type)
+       ,@(if crypt-label
+             '((dependencies mapped-devices))
+             '()))))
 
 (define (user-partitions->file-systems user-partitions)
   "Convert the given USER-PARTITIONS list of <user-partition> records into a
@@ -1139,6 +1226,16 @@ list of <file-system> records."
             (user-partition->file-system user-partition))))
    user-partitions))
 
+(define (user-partition->mapped-device user-partition)
+  "Convert the given USER-PARTITION record into a MAPPED-DEVICE record
+from (gnu system mapped-devices) and return it."
+  (let ((label (user-partition-crypt-label user-partition))
+        (path (user-partition-path user-partition)))
+    `(mapped-device
+      (source (uuid ,(uuid->string (read-partition-uuid path))))
+      (target ,label)
+      (type luks-device-mapping))))
+
 (define (bootloader-configuration user-partitions)
   "Return the bootloader configuration field for USER-PARTITIONS."
   (let* ((root-partition
@@ -1159,11 +1256,18 @@ list of <file-system> records."
 (define (user-partitions->configuration user-partitions)
   "Return the configuration field for USER-PARTITIONS."
   (let* ((swap-user-partitions (find-swap-user-partitions user-partitions))
-         (swap-devices (map user-partition-path swap-user-partitions)))
+         (swap-devices (map user-partition-path swap-user-partitions))
+         (crypted-partitions
+          (filter user-partition-crypt-label user-partitions)))
     `(,@(if (null? swap-devices)
             '()
             `((swap-devices (list ,@swap-devices))))
       (bootloader ,@(bootloader-configuration user-partitions))
+      ,@(if (null? crypted-partitions)
+            '()
+            `((mapped-devices
+               (list ,@(map user-partition->mapped-device
+                            crypted-partitions)))))
       (file-systems (cons*
                      ,@(user-partitions->file-systems user-partitions)
                      %base-file-systems)))))