[bug#77885] gnu: security-token: create pam-u2f service with pam extension

Message ID c91b9020282549e425a9c6db992ffa23f950f11c.1744911678.git.scmorris.dev@gmail.com
State New
Headers
Series [bug#77885] gnu: security-token: create pam-u2f service with pam extension |

Commit Message

scmorris.dev@gmail.com April 17, 2025, 5:41 p.m. UTC
  From: Samuel Morris <scmorris.dev@gmail.com>

Adding this pam extension allows users to configure their security
key to authenticate in various ways through PAM modules, such as
accessing root privileges.

The pam_u2f module has many arguments. I have only exposed the control
level and the cue_prompt for now. See the module documentation for more
details: https://developers.yubico.com/pam-u2f/

Also, this is my first time contributing. I had a very hard time
getting my Yubikey working properly, so I thought I’d share my changes. I
am booting guix on my framework and currently using my Yubikey with these
changes for login/sudo/su authentication. That's about the extent of my
testing. If this basically looks right, then I can add some documentation
as well and extend the service configuration with more arguments from the
module.


Change-Id: I9a0ba767d7f9288892868f71c0f2595d70df237d
---
 gnu/services/security-token.scm | 47 ++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)


base-commit: 812f972f046e521eabc3ddd76e790d7a69d426b5
  

Patch

diff --git a/gnu/services/security-token.scm b/gnu/services/security-token.scm
index 7d6c0e0f8d..dcff42933b 100644
--- a/gnu/services/security-token.scm
+++ b/gnu/services/security-token.scm
@@ -20,17 +20,25 @@ 
 
 (define-module (gnu services security-token)
   #:use-module (gnu services)
+  #:use-module (gnu services configuration)
   #:use-module (gnu services shepherd)
   #:use-module (gnu packages admin)
   #:use-module (gnu packages base)
   #:use-module (gnu packages security-token)
+  #:use-module (gnu system pam)
   #:use-module (gnu system shadow)
   #:use-module (guix gexp)
   #:use-module (guix modules)
   #:use-module (guix records)
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-26)
-  #:export (pcscd-configuration
+  #:export (pam-u2f-configuration
+            pam-u2f-configuration?
+            pam-u2f-configuration-prompt
+            pam-u2f-configuration-module
+            pam-u2f-configuration-control
+            pam-u2f-service-type
+            pcscd-configuration
             pcscd-configuration?
             pcscd-configuration-pcsc-lite
             pcscd-configuration-usb-drivers
@@ -90,3 +98,40 @@  (define pcscd-service-type
           (service-extension activation-service-type
                              pcscd-activation)))
    (default-value (pcscd-configuration))))
+
+(define-configuration/no-serialization pam-u2f-configuration
+  (control
+   (string "sufficient")
+   "Control level for this pam module [sufficient, required]")
+  (prompt
+   (string "Tap your security key")
+   "Cue prompt to be printed when the security key is accessed."))
+
+(define (pam-u2f-extension-procedure config)
+  "Return an extension for PAM-ROOT-SERVICE-TYPE that ensures that all the PAM
+services use 'pam_u2f.so', a module implementing PAM over U2F, providing an
+easy way to integrate the YubiKey (or other U2F compliant authenticators) into
+your existing infrastructure.)"
+  (match-record config <pam-u2f-configuration>
+                (control prompt)
+    (let ((pam-u2f-entry
+           (pam-entry
+            (control control)
+            (module (file-append pam-u2f "/lib/security/pam_u2f.so"))
+            (arguments `("cue" (simple-format #f "[cue_prompt=~A]" ,prompt))))))
+      (list (pam-extension
+             (transformer
+              (lambda (pam)
+                (pam-service
+                 (inherit pam)
+                 (auth (cons pam-u2f-entry (pam-service-auth pam)))))))))))
+
+(define pam-u2f-service-type
+  (service-type
+   (name 'pam-u2f)
+   (description "Configure and integrate u2f with pam.")
+   (extensions
+    (list
+     (service-extension pam-root-service-type
+                        pam-u2f-extension-procedure)))
+   (default-value (pam-u2f-configuration))))