Use error message wordings for permissions checks on .pgpass and SSL private

key files that are similar to the one for the postmaster's data directory
permissions check.  (I chose to standardize on that one since it's the most
heavily used and presumably best-wordsmithed by now.)  Also eliminate explicit
tests on file ownership in these places, since the ensuing read attempt must
fail anyway if it's wrong, and there seems no value in issuing the same error
message for distinct problems.  (But I left in the explicit ownership test in
postmaster.c, since it had its own error message anyway.)  Also be more
specific in the documentation's descriptions of these checks.  Per a gripe
from Kevin Hunter.
This commit is contained in:
Tom Lane 2008-03-31 02:43:14 +00:00
parent c5f11f9d19
commit 3405f2b925
6 changed files with 39 additions and 24 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.256 2008/03/06 15:37:56 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.257 2008/03/31 02:43:14 tgl Exp $ -->
<chapter id="libpq"> <chapter id="libpq">
<title><application>libpq</application> - C Library</title> <title><application>libpq</application> - C Library</title>
@ -5223,11 +5223,13 @@ defaultNoticeProcessor(void *arg, const char *message)
authorities (<acronym>CA</acronym>) trusted by the server. A matching authorities (<acronym>CA</acronym>) trusted by the server. A matching
private key file <filename>~/.postgresql/postgresql.key</> must also private key file <filename>~/.postgresql/postgresql.key</> must also
be present, unless the secret key for the certificate is stored in a be present, unless the secret key for the certificate is stored in a
hardware token, as specified by <envar>PGSSLKEY</envar>. (On Microsoft hardware token, as specified by <envar>PGSSLKEY</envar>. The private
Windows these files are named key file must not allow any access to world or group; achieve this by the
command <command>chmod 0600 ~/.postgresql/postgresql.key</command>.
On Microsoft Windows these files are named
<filename>%APPDATA%\postgresql\postgresql.crt</filename> and <filename>%APPDATA%\postgresql\postgresql.crt</filename> and
<filename>%APPDATA%\postgresql\postgresql.key</filename>.) The private <filename>%APPDATA%\postgresql\postgresql.key</filename>, and there
key file must not be world-readable. is no special permissions check since the directory is presumed secure.
</para> </para>
<para> <para>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.410 2008/03/21 14:23:37 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.411 2008/03/31 02:43:14 tgl Exp $ -->
<chapter Id="runtime"> <chapter Id="runtime">
<title>Operating System Environment</title> <title>Operating System Environment</title>
@ -1632,7 +1632,11 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
To start in <acronym>SSL</> mode, the files <filename>server.crt</> To start in <acronym>SSL</> mode, the files <filename>server.crt</>
and <filename>server.key</> must exist in the server's data directory. and <filename>server.key</> must exist in the server's data directory.
These files should contain the server certificate and private key, These files should contain the server certificate and private key,
respectively. If the private key is protected with a passphrase, the respectively.
On Unix systems, the permissions on <filename>server.key</filename> must
disallow any access to world or group; achieve this by the command
<command>chmod 0600 server.key</command>.
If the private key is protected with a passphrase, the
server will prompt for the passphrase and will not start until it has server will prompt for the passphrase and will not start until it has
been entered. been entered.
</para> </para>
@ -1731,10 +1735,15 @@ rm privkey.pem
Enter the old passphrase to unlock the existing key. Now do: Enter the old passphrase to unlock the existing key. Now do:
<programlisting> <programlisting>
openssl req -x509 -in server.req -text -key server.key -out server.crt openssl req -x509 -in server.req -text -key server.key -out server.crt
chmod og-rwx server.key
</programlisting> </programlisting>
to turn the certificate into a self-signed certificate and to copy to turn the certificate into a self-signed certificate and to copy
the key and certificate to where the server will look for them. the key and certificate to where the server will look for them.
Finally do
<programlisting>
chmod og-rwx server.key
</programlisting>
because the server will reject the file if its permissions are more
liberal than this.
For more details on how to create your server private key and For more details on how to create your server private key and
certificate, refer to the <productname>OpenSSL</> documentation. certificate, refer to the <productname>OpenSSL</> documentation.
</para> </para>

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.83 2008/01/01 19:45:49 momjian Exp $ * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.84 2008/03/31 02:43:14 tgl Exp $
* *
* Since the server static private key ($DataDir/server.key) * Since the server static private key ($DataDir/server.key)
* will normally be stored unencrypted so that the database * will normally be stored unencrypted so that the database
@ -735,7 +735,7 @@ initialize_SSL(void)
errmsg("could not load server certificate file \"%s\": %s", errmsg("could not load server certificate file \"%s\": %s",
SERVER_CERT_FILE, SSLerrmessage()))); SERVER_CERT_FILE, SSLerrmessage())));
if (stat(SERVER_PRIVATE_KEY_FILE, &buf) == -1) if (stat(SERVER_PRIVATE_KEY_FILE, &buf) != 0)
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not access private key file \"%s\": %m", errmsg("could not access private key file \"%s\": %m",
@ -750,13 +750,12 @@ initialize_SSL(void)
* directory permission check in postmaster.c) * directory permission check in postmaster.c)
*/ */
#if !defined(WIN32) && !defined(__CYGWIN__) #if !defined(WIN32) && !defined(__CYGWIN__)
if (!S_ISREG(buf.st_mode) || (buf.st_mode & (S_IRWXG | S_IRWXO)) || if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
buf.st_uid != geteuid())
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unsafe permissions on private key file \"%s\"", errmsg("private key file \"%s\" has group or world access",
SERVER_PRIVATE_KEY_FILE), SERVER_PRIVATE_KEY_FILE),
errdetail("File must be owned by the database user and must have no permissions for \"group\" or \"other\"."))); errdetail("Permissions should be u=rw (0600) or less.")));
#endif #endif
if (!SSL_CTX_use_PrivateKey_file(SSL_context, if (!SSL_CTX_use_PrivateKey_file(SSL_context,

View File

@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.553 2008/03/09 04:56:28 tgl Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.554 2008/03/31 02:43:14 tgl Exp $
* *
* NOTES * NOTES
* *
@ -1053,6 +1053,13 @@ checkDataDir(void)
DataDir))); DataDir)));
} }
/* eventual chdir would fail anyway, but let's test ... */
if (!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("specified data directory \"%s\" is not a directory",
DataDir)));
/* /*
* Check that the directory belongs to my userid; if not, reject. * Check that the directory belongs to my userid; if not, reject.
* *

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.356 2008/01/29 02:06:30 tgl Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.357 2008/03/31 02:43:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -3718,11 +3718,10 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
} }
/* If password file cannot be opened, ignore it. */ /* If password file cannot be opened, ignore it. */
if (stat(pgpassfile, &stat_buf) == -1) if (stat(pgpassfile, &stat_buf) != 0)
return NULL; return NULL;
#ifndef WIN32 #ifndef WIN32
if (!S_ISREG(stat_buf.st_mode)) if (!S_ISREG(stat_buf.st_mode))
{ {
fprintf(stderr, fprintf(stderr,
@ -3735,7 +3734,7 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
{ {
fprintf(stderr, fprintf(stderr,
libpq_gettext("WARNING: password file \"%s\" has world or group read access; permission should be u=rw (0600)\n"), libpq_gettext("WARNING: password file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
pgpassfile); pgpassfile);
return NULL; return NULL;
} }

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.103 2008/02/16 21:03:30 momjian Exp $ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.104 2008/03/31 02:43:14 tgl Exp $
* *
* NOTES * NOTES
* [ Most of these notes are wrong/obsolete, but perhaps not all ] * [ Most of these notes are wrong/obsolete, but perhaps not all ]
@ -703,7 +703,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
{ {
/* read the user key from file */ /* read the user key from file */
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE); snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
if (stat(fnbuf, &buf) == -1) if (stat(fnbuf, &buf) != 0)
{ {
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate present, but not private key file \"%s\"\n"), libpq_gettext("certificate present, but not private key file \"%s\"\n"),
@ -712,11 +712,10 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
return 0; return 0;
} }
#ifndef WIN32 #ifndef WIN32
if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) || if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
buf.st_uid != geteuid())
{ {
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("private key file \"%s\" has wrong permissions\n"), libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
fnbuf); fnbuf);
ERR_pop_to_mark(); ERR_pop_to_mark();
return 0; return 0;