From 16dda01f371f033e0df75d80127643605df7830f Mon Sep 17 00:00:00 2001 From: Dimitri Fontaine Date: Thu, 15 Nov 2018 00:13:21 +0100 Subject: [PATCH] Deal with SSL verify error the wrong way. This patch adds an option --no-ssl-cert-verification that allows bypassing OpenSSL server certificate verification. It's hopefully a temporary measure that we set up in order to make progress when confronted to: SSL verify error: 20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY The real solution is of course to install the SSL certificates at a place where pgloader will look for them, which defaults to ~/.postgresql/postgresql.crt at the moment. It's not clear what the story is with the defaults from /etc/ssl, or how to make things happen in a better way. See #648, See #679, See #768, See #748, See #775. --- src/main.lisp | 14 ++++++++++++- src/pgsql/connection.lisp | 43 +++++++++++++++++++++++++++++---------- src/utils/threads.lisp | 6 +++++- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/main.lisp b/src/main.lisp index a317232..c8e43f7 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -51,6 +51,10 @@ ("on-error-stop" :type boolean :documentation "Refrain from handling errors properly.") + ("no-ssl-cert-verification" + :type boolean + :documentation "Instruct OpenSSL to bypass verifying certificates.") + (("context" #\C) :type string :documentation "Command Context Variables") (("with") :type string :list t :optional t @@ -197,6 +201,7 @@ client-min-messages log-min-messages summary root-dir self-upgrade with set field cast type encoding before after + no-ssl-cert-verification regress) options @@ -249,11 +254,15 @@ (lisp-implementation-type) (lisp-implementation-version))) - (when help + (when (or help) (usage argv)) (when (or help version) (uiop:quit +os-code-success+)) + (when (null arguments) + (usage argv) + (uiop:quit +os-code-error-usage+)) + (when list-encodings (show-encodings) (uiop:quit +os-code-success+)) @@ -316,6 +325,9 @@ (uiop:native-namestring *log-filename*)) (log-message :log "Data errors in '~a'~%" *root-dir*) + (when no-ssl-cert-verification + (setf cl+ssl:*make-ssl-client-stream-verify-default* nil)) + (cond ((and regress (= 1 (length arguments))) (process-regression-test (first arguments))) diff --git a/src/pgsql/connection.lisp b/src/pgsql/connection.lisp index 63af2af..9896559 100644 --- a/src/pgsql/connection.lisp +++ b/src/pgsql/connection.lisp @@ -118,7 +118,19 @@ (uiop:native-namestring crt-file))) (pomo::*ssl-key-file* (when (and (ssl-enable-p pgconn) (probe-file key-file)) - (uiop:native-namestring key-file)))) + (uiop:native-namestring key-file))) + ;; + ;; It's ok to set :verify-mode to NONE here because + ;; cl+ssl:*make-ssl-client-stream-verify-default* defaults to + ;; :require and takes precedence. + ;; + ;; Only when --no-ssl-cert-verification is passed as a command line + ;; option do we set cl+ssl:*make-ssl-client-stream-verify-default* + ;; to NIL, then allowing the NONE behaviour set here. + ;; + (ssl-context + (CL+SSL:MAKE-CONTEXT :disabled-protocols nil + :verify-mode CL+SSL:+SSL-VERIFY-NONE+))) (flet ((connect (pgconn username) (handler-case ;; in some cases (client_min_messages set to debug5 @@ -128,20 +140,29 @@ #'(lambda (w) (log-message :warning "~a" w) (muffle-warning)))) - (pomo:connect (db-name pgconn) - (or username (db-user pgconn)) - (db-pass pgconn) - (let ((host (db-host pgconn))) - (if (and (consp host) (eq :unix (car host))) - :unix - host)) - :port (db-port pgconn) - :use-ssl (or (pgconn-use-ssl pgconn) :no))) + (CL+SSL:WITH-GLOBAL-CONTEXT (ssl-context :auto-free-p t) + (pomo:connect (db-name pgconn) + (or username (db-user pgconn)) + (db-pass pgconn) + (let ((host (db-host pgconn))) + (if (and (consp host) (eq :unix (car host))) + :unix + host)) + :port (db-port pgconn) + :use-ssl (or (pgconn-use-ssl pgconn) :no)))) + ((or too-many-connections configuration-limit-exceeded) (e) (log-message :error "Failed to connect to ~a: ~a; will try again in ~fs" pgconn e *retry-connect-delay*) - (sleep *retry-connect-delay*))))) + (sleep *retry-connect-delay*)) + + (CL+SSL:SSL-ERROR-VERIFY (e) + (log-message :error + "Connecting to PostgreSQL ~a: ~a" + (db-host pgconn) e) + (log-message :log "You may try --no-ssl-cert-verification") + (error e))))) (loop :while (null (conn-handle pgconn)) :repeat *retry-connect-times* :do (setf (conn-handle pgconn) (connect pgconn username)))) diff --git a/src/utils/threads.lisp b/src/utils/threads.lisp index a2776ce..2581579 100644 --- a/src/utils/threads.lisp +++ b/src/utils/threads.lisp @@ -28,6 +28,10 @@ ;; bindings updates for libs ;; CFFI is used by the SQLite lib (cffi:*default-foreign-encoding* - . ,cffi:*default-foreign-encoding*)))) + . ,cffi:*default-foreign-encoding*) + + ;; CL+SSL can be picky about verifying certs + (cl+ssl:*make-ssl-client-stream-verify-default* + . ,cl+ssl:*make-ssl-client-stream-verify-default*)))) "Wrapper around lparallel:make-kernel that sets our usual bindings." (lp:make-kernel worker-count :bindings bindings))