aboutsummaryrefslogtreecommitdiff
;;; Whispers --- Stealth VPN and ssh tunneler
;;; Copyright © 2023 Runciter <runciter@whispers-vpn.org>
;;;
;;; This file is part of Whispers.
;;;
;;; Whispers is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; Whispers is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with Whispers.  If not, see <http://www.gnu.org/licenses/>.

(define-module (whispers services ssh-agent)
  #:use-module (guix gexp)
  #:use-module (guix records)
  #:use-module (gnu services)
  #:use-module (gnu services shepherd)
  #:use-module (gnu services admin)
  #:use-module (gnu packages ssh)
  #:export (ssh-agent-configuration
            ssh-agent-configuration?
            ssh-agent-service-type))

(define-record-type* <ssh-agent-configuration>
  ssh-agent-configuration make-ssh-agent-configuration
  ssh-agent-configuration?
  this-ssh-agent-configuration
  ;; A file-like object
  (ssh-package          ssh-agent-configuration-ssh-package
                        (default openssh))
  ;; A string
  (socket-folder        ssh-agent-configuration-socket-folder
                        (default "/var/run/ssh-agent"))
  ;; A string
  (socket-file-name     ssh-agent-configuration-socket-file-name
                        (default "ssh-agent.sock"))
  ;; A string
  (log-folder           ssh-agent-configuration-log-folder
                        (default "/var/log"))
  ;; A string
  (log-file-name        ssh-agent-configuration-log-file-name
                        (default "ssh-agent.log"))
  ;; A list of strings
  (auto-added-keys      ssh-agent-configuration-auto-added-keys
                        (default '()))
  ;; A boolean value
  (%auto-start?         ssh-agent-configuration-auto-start?
                        (default #t)))

(define (socket-file-path config)
  "Returns a string specifying the path to the log file of an ssh agent
service configurable by CONFIG, a record of the
<ssh-agent-configuration> type."
  (string-append (ssh-agent-configuration-socket-folder config)
                 "/"
                 (ssh-agent-configuration-socket-file-name config)))

(define (log-file-path config)
  "Returns a string specifying the path to the log file of an ssh agent
service configurable by CONFIG, a record of the
<ssh-agent-configuration> type."
  (string-append (ssh-agent-configuration-log-folder config)
                 "/"
                 (ssh-agent-configuration-log-file-name config)))

(define (ssh-agent-log-rotation config)
  "Returns a list of log-rotation records specifying how to rotate the
logs of as ssh aggent service configurable by CONFIG, a record of
the <ssh-agent-configuration> type."
  (list (log-rotation (frequency 'daily)
                      (files `(,(log-file-path config))))))

(define (add-key-procedure config)
  "Returns a G-exp to a procedure adding a private key to a running ssh
agent daemon, configurable by CONFIG, a record of the
<ssh-agent-configuration> type."
  (let ((ssh-package (ssh-agent-configuration-ssh-package config)))
    #~(lambda (running key-path)
        ((make-system-constructor
          (string-append "SSH_AUTH_SOCK="
                         #$(socket-file-path config)
                         " "
                         #$(file-append ssh-package
                                        "/bin/ssh-add")
                         " "
                         key-path))))))

(define (constructor-gexp config)
  "Returns a G-exp to a procedure adding a private key to a running ssh
agent daemon, configurable by CONFIG, a record of the
<ssh-agent-configuration> type."
  (let ((ssh-package (ssh-agent-configuration-ssh-package config))
        (auto-added-keys (ssh-agent-configuration-auto-added-keys config))
        (socket-file-path (socket-file-path config))
        (log-file-path (log-file-path config)))
    #~(lambda whatever
        (let ((ret ((make-forkexec-constructor
                     (list #$(file-append ssh-package
                                          "/bin/ssh-agent")
                           "-d"
                           "-a"
                           #$socket-file-path)
                     #:log-file
                     #$log-file-path))))
          (map (lambda (key)
                 (action 'ssh-agent 'add-key key))
               '#$auto-added-keys)
          ret))))

(define (ssh-agent-shepherd-services config)
  "Returns a list of shepherd services handling an ssh agent daemon
configured by CONFIG, a record of the <ssh-agent-configuration>
type."
  (let ((auto-start? (ssh-agent-configuration-auto-start? config)))
    (list
     (shepherd-service
      (documentation (string-append "Ssh agent service, socket file can
be found at "
                                    (socket-file-path config)
                                    "."))
      (provision '(ssh-agent))
      (requirement '())
      (start (constructor-gexp config))
      (stop #~(make-kill-destructor))
      (actions
       (list
        (shepherd-action (name 'add-key)
                         (documentation "Add the private key found at at
the path KEY-PATH to a started ssh-agent daemon.")
                         (procedure (add-key-procedure config)))))
      (auto-start? auto-start?)))))

(define ssh-agent-service-type
  (service-type
   (name 'ssh-agent)
   (description "Ssh agent service")
   (extensions
    (list (service-extension shepherd-root-service-type
                             ssh-agent-shepherd-services)
          (service-extension rottlog-service-type
                             ssh-agent-log-rotation)
          (service-extension
           profile-service-type
           (lambda (config)
             (list
              (ssh-agent-configuration-ssh-package config))))))
   (default-value (ssh-agent-configuration))))