diff options
Diffstat (limited to 'debian/patches/sudo-ensure-that-stdin-is-a-pipe-never-a.patch')
-rw-r--r-- | debian/patches/sudo-ensure-that-stdin-is-a-pipe-never-a.patch | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/debian/patches/sudo-ensure-that-stdin-is-a-pipe-never-a.patch b/debian/patches/sudo-ensure-that-stdin-is-a-pipe-never-a.patch new file mode 100644 index 0000000..3a918dc --- /dev/null +++ b/debian/patches/sudo-ensure-that-stdin-is-a-pipe-never-a.patch @@ -0,0 +1,153 @@ +From: Sean Whitton <spwhitton@spwhitton.name> +Date: Thu, 22 Jul 2021 15:20:09 -0700 +X-Dgit-Generated: 0.8.0-2 7b0c6d72899a5946b1fbc4c495de4b1458e72779 +Subject: :SUDO: ensure that stdin is a pipe, never a real file + +Signed-off-by: Sean Whitton <spwhitton@spwhitton.name> +(cherry picked from commit 56dda681a644833f9b7de1775b7d193fd120bb8e) + +--- + +--- consfigurator-0.8.0.orig/doc/connections.rst ++++ consfigurator-0.8.0/doc/connections.rst +@@ -97,7 +97,9 @@ Consfigurator sends your sudo password o + password is required is violated, your sudo password will end up in the stdin + to whatever command is being run using sudo. There is no facility for + directly passing in a passphrase; you must use ``:AS`` to obtain passwords +-from sources of prerequisite data. ++from sources of prerequisite data. The passphrase will be written to a ++private temporary file which is deleted when the ``:SUDO`` connection is torn ++down. + + If any connection types which start up remote Lisp images occur before a + ``:SUDO`` entry in your connection chain, ``ESTABLISH-CONNECTION`` will need +--- consfigurator-0.8.0.orig/src/connection/sudo.lisp ++++ consfigurator-0.8.0/src/connection/sudo.lisp +@@ -35,6 +35,22 @@ + (get-data-protected-string + (strcat "--user-passwd--" host) user))))) + ++;; With sudo -S, we must ensure that sudo's stdin is a pipe, not a file, ++;; because otherwise the program sudo invokes may rewind(stdin) and read the ++;; password, intentionally or otherwise. And UIOP:RUN-PROGRAM empties input ++;; streams into temporary files, so there is the potential for this to happen ++;; when using :SUDO to apply properties to localhost. Other connection types ++;; might work similarly. ++;; ++;; The simplest way to handle this would be to just put 'cat |' at the ++;; beginning of the shell command we construct, but that relies on cat(1) not ++;; calling rewind(stdin) either. So we write the password input out to a ++;; temporary file ourselves, and use cat(1) to concatenate that file with the ++;; actual input. ++ ++(defclass sudo-connection (shell-wrap-connection) ++ ((password-file :initarg :password-file))) ++ + (defmethod establish-connection ((type (eql :sudo)) + remaining + &key +@@ -42,56 +58,41 @@ + password) + (declare (ignore remaining)) + (informat 1 "~&Establishing sudo connection to ~A" user) +- (make-instance 'sudo-connection +- :connattrs `(:remote-user ,user) +- ;; we'll send the password followed by ^M, then the real +- ;; stdin. use CODE-CHAR in this way so that we can be sure +- ;; ASCII ^M is what will get emitted. +- :password (and password +- (make-passphrase +- (strcat (passphrase password) +- (string (code-char 13))))))) +- +-(defclass sudo-connection (shell-wrap-connection) +- ((password :initarg :password))) +- +-(defmethod get-sudo-password ((connection sudo-connection)) +- (let ((value (slot-value connection 'password))) +- (and value (passphrase value)))) +- +-(defmethod connection-shell-wrap ((connection sudo-connection) cmd) +- ;; Wrap in sh -c so that it is more likely we are either asked for a +- ;; password for all our commands or not asked for one for any. +- ;; +- ;; Preserve SSH_AUTH_SOCK for root to enable this sort of workflow: deploy +- ;; laptop using (:SUDO :SBCL) and then DEFHOST for laptop contains (DEPLOYS +- ;; ((:SSH :TO "root")) ...) to deploy a VM running on the laptop. +- ;; +- ;; This only works for sudoing to root because only the superuser can access +- ;; the socket (and was always able to, so we're not granting new access +- ;; which may be unwanted). +- (let ((user (connection-connattr connection :remote-user))) +- (format +- nil +-"sudo -HkS --prompt=\"\" ~:[~;--preserve-env=SSH_AUTH_SOCK ~]--user=~A sh -c ~A" +- (string= user "root") user (escape-sh-token cmd)))) +- +-(defmethod connection-run ((c sudo-connection) cmd (input null)) +- (call-next-method c cmd (get-sudo-password c))) +- +-(defmethod connection-run ((c sudo-connection) cmd (input string)) +- (call-next-method c cmd (strcat (get-sudo-password c) input))) +- +-(defmethod connection-run ((connection sudo-connection) cmd (input stream)) +- (call-next-method connection +- cmd +- (if-let ((password (get-sudo-password connection))) +- (make-concatenated-stream +- (if (subtypep (stream-element-type input) 'character) +- (make-string-input-stream password) +- (babel-streams:make-in-memory-input-stream +- (babel:string-to-octets +- password :encoding :UTF-8) +- :element-type (stream-element-type input))) +- input) +- input))) ++ (make-instance ++ 'sudo-connection ++ :connattrs `(:remote-user ,user) ++ :password-file (and password ++ (let ((file (mktemp))) ++ ;; We'll send the password followed by ^M, then the ++ ;; real stdin. Use CODE-CHAR in this way so that we ++ ;; can be sure ASCII ^M is what will get emitted. ++ (writefile file (strcat (passphrase password) ++ (string (code-char 13))) ++ :mode #o600) ++ file)))) ++ ++(defmethod connection-teardown :after ((connection sudo-connection)) ++ (when-let ((file (slot-value connection 'password-file))) ++ (delete-remote-trees file))) ++ ++(defmethod connection-run ((connection sudo-connection) cmd input) ++ (let* ((file (slot-value connection 'password-file)) ++ (user (connection-connattr connection :remote-user)) ++ (prefix (if file ++ (format nil "cat ~A - | sudo -HkS --prompt=\"\"" ++ (escape-sh-token file)) ++ "sudo -Hkn"))) ++ ;; Wrap in sh -c so that it is more likely we are either asked for a ++ ;; password for all our commands or not asked for one for any. ++ ;; ++ ;; Preserve SSH_AUTH_SOCK for root to enable this sort of workflow: deploy ++ ;; laptop using (:SUDO :SBCL) and then DEFHOST for laptop contains ++ ;; (DEPLOYS ((:SSH :TO "root")) ...) to deploy a VM running on the laptop. ++ ;; ++ ;; This only works for sudoing to root because only the superuser can ++ ;; access the socket (and was always able to, so we're not granting new ++ ;; access which may be unwanted). ++ (mrun :may-fail :input input ++ (format nil ++ "~A ~:[~;--preserve-env=SSH_AUTH_SOCK ~]--user=~A sh -c ~A" ++ prefix (string= user "root") user (escape-sh-token cmd))))) +--- consfigurator-0.8.0.orig/src/package.lisp ++++ consfigurator-0.8.0/src/package.lisp +@@ -121,6 +121,7 @@ + #:run + #:mrun + #:with-remote-temporary-file ++ #:mktemp + #:with-remote-current-directory + #:run-failed + #:runlines |