Allow root-owned SSL private keys in libpq, not only the backend.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 28 Feb 2022 19:12:52 +0000 (14:12 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 28 Feb 2022 19:12:52 +0000 (14:12 -0500)
This change makes libpq apply the same private-key-file ownership
and permissions checks that we have used in the backend since commit
9a83564c5.  Namely, that the private key can be owned by either the
current user or root (with different file permissions allowed in the
two cases).  This allows system-wide management of key files, which
is just as sensible on the client side as the server, particularly
when the client is itself some application daemon.

Sync the comments about this between libpq and the backend, too.

David Steele

Discussion: https://postgr.es/m/f4b7bc55-97ac-9e69-7398-335e212f7743@pgmasters.net

src/backend/libpq/be-secure-common.c
src/interfaces/libpq/fe-secure-openssl.c

index 7e9a64d08e61ff15b10b217efd72667d8799818c..7a9de524db6eac307aed94cf83c75c55c26e1d25 100644 (file)
@@ -143,6 +143,7 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
                return false;
        }
 
+       /* Key file must be a regular file */
        if (!S_ISREG(buf.st_mode))
        {
                ereport(loglevel,
@@ -153,9 +154,19 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
        }
 
        /*
-        * Refuse to load key files owned by users other than us or root.
+        * Refuse to load key files owned by users other than us or root, and
+        * require no public access to the key file.  If the file is owned by us,
+        * require mode 0600 or less.  If owned by root, require 0640 or less to
+        * allow read access through either our gid or a supplementary gid that
+        * allows us to read system-wide certificates.
         *
-        * XXX surely we can check this on Windows somehow, too.
+        * Note that similar checks are performed in
+        * src/interfaces/libpq/fe-secure-openssl.c so any changes here may need
+        * to be made there as well.
+        *
+        * Ideally we would do similar permissions checks on Windows, but it is
+        * not clear how that would work since Unix-style permissions may not be
+        * available.
         */
 #if !defined(WIN32) && !defined(__CYGWIN__)
        if (buf.st_uid != geteuid() && buf.st_uid != 0)
@@ -166,20 +177,7 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
                                                ssl_key_file)));
                return false;
        }
-#endif
 
-       /*
-        * Require no public access to key file. If the file is owned by us,
-        * require mode 0600 or less. If owned by root, require 0640 or less to
-        * allow read access through our gid, or a supplementary gid that allows
-        * to read system-wide certificates.
-        *
-        * XXX temporarily suppress check when on Windows, because there may not
-        * be proper support for Unix-y file permissions.  Need to think of a
-        * reasonable check to apply on Windows.  (See also the data directory
-        * permission check in postmaster.c)
-        */
-#if !defined(WIN32) && !defined(__CYGWIN__)
        if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
                (buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
        {
index f6e563a2e5057cbcbfb7753390e741cf06e8d8dd..d81218a4ccdec9ebe6be629d6e71d6c0c2b493b5 100644 (file)
@@ -1245,11 +1245,45 @@ initialize_SSL(PGconn *conn)
                                                                  fnbuf);
                        return -1;
                }
-#ifndef WIN32
-               if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
+
+               /* Key file must be a regular file */
+               if (!S_ISREG(buf.st_mode))
+               {
+                       appendPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("private key file \"%s\" is not a regular file"),
+                                                         fnbuf);
+                       return -1;
+               }
+
+               /*
+                * Refuse to load key files owned by users other than us or root, and
+                * require no public access to the key file.  If the file is owned by
+                * us, require mode 0600 or less.  If owned by root, require 0640 or
+                * less to allow read access through either our gid or a supplementary
+                * gid that allows us to read system-wide certificates.
+                *
+                * Note that similar checks are performed in
+                * src/backend/libpq/be-secure-common.c so any changes here may need
+                * to be made there as well.
+                *
+                * Ideally we would do similar permissions checks on Windows, but it
+                * is not clear how that would work since Unix-style permissions may
+                * not be available.
+                */
+#if !defined(WIN32) && !defined(__CYGWIN__)
+               if (buf.st_uid != geteuid() && buf.st_uid != 0)
+               {
+                       appendPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("private key file \"%s\" must be owned by the current user or root\n"),
+                                                         fnbuf);
+                       return -1;
+               }
+
+               if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
+                       (buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
                {
                        appendPQExpBuffer(&conn->errorMessage,
-                                                         libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
+                                                         libpq_gettext("private key file \"%s\" has group or world access; file must have permissions u=rw (0600) or less if owned by the current user, or permissions u=rw,g=r (0640) or less if owned by root\n"),
                                                          fnbuf);
                        return -1;
                }