diff --git a/src/backend/libpq/be-secure-common.c b/src/backend/libpq/be-secure-common.c index e8b837d1fa78d..3fbfba39fcd77 100644 --- a/src/backend/libpq/be-secure-common.c +++ b/src/backend/libpq/be-secure-common.c @@ -36,142 +36,125 @@ * The result will be put in buffer buf, which is of size size. The return * value is the length of the actual result. */ -int -run_ssl_passphrase_command(const char *prompt, bool is_server_start, char *buf, int size) -{ - int loglevel = is_server_start ? ERROR : LOG; - char *command; - FILE *fh; - int pclose_rc; - size_t len = 0; - - Assert(prompt); - Assert(size > 0); - buf[0] = '\0'; - - command = replace_percent_placeholders(ssl_passphrase_command, "ssl_passphrase_command", "p", prompt); - - fh = OpenPipeStream(command, "r"); - if (fh == NULL) - { - ereport(loglevel, - (errcode_for_file_access(), - errmsg("could not execute command \"%s\": %m", - command))); - goto error; - } - - if (!fgets(buf, size, fh)) - { - if (ferror(fh)) - { - explicit_bzero(buf, size); - ereport(loglevel, - (errcode_for_file_access(), - errmsg("could not read from command \"%s\": %m", - command))); - goto error; - } - } - - pclose_rc = ClosePipeStream(fh); - if (pclose_rc == -1) - { - explicit_bzero(buf, size); - ereport(loglevel, - (errcode_for_file_access(), - errmsg("could not close pipe to external command: %m"))); - goto error; - } - else if (pclose_rc != 0) - { - char *reason; - - explicit_bzero(buf, size); - reason = wait_result_to_str(pclose_rc); - ereport(loglevel, - (errcode_for_file_access(), - errmsg("command \"%s\" failed", - command), - errdetail_internal("%s", reason))); - pfree(reason); - goto error; - } - - /* strip trailing newline and carriage return */ - len = pg_strip_crlf(buf); +int run_ssl_passphrase_command(const char *prompt, bool is_server_start, + char *buf, int size) { + int loglevel = is_server_start ? ERROR : LOG; + char *command; + FILE *fh; + int pclose_rc; + size_t len = 0; + + Assert(prompt); + Assert(size > 0); + buf[0] = '\0'; + + command = replace_percent_placeholders(ssl_passphrase_command, + "ssl_passphrase_command", "p", prompt); + + fh = OpenPipeStream(command, "r"); + if (fh == NULL) { + ereport(loglevel, + (errcode_for_file_access(), + errmsg("could not execute command \"%s\": %m", command))); + goto error; + } + + if (!fgets(buf, size, fh)) { + if (ferror(fh)) { + explicit_bzero(buf, size); + ereport(loglevel, + (errcode_for_file_access(), + errmsg("could not read from command \"%s\": %m", command))); + goto error; + } + } + + pclose_rc = ClosePipeStream(fh); + if (pclose_rc == -1) { + explicit_bzero(buf, size); + ereport(loglevel, (errcode_for_file_access(), + errmsg("could not close pipe to external command: %m"))); + goto error; + } else if (pclose_rc != 0) { + char *reason; + + explicit_bzero(buf, size); + reason = wait_result_to_str(pclose_rc); + ereport(loglevel, (errcode_for_file_access(), + errmsg("command \"%s\" failed", command), + errdetail_internal("%s", reason))); + pfree(reason); + goto error; + } + + /* strip trailing newline and carriage return */ + len = pg_strip_crlf(buf); error: - pfree(command); - return len; + pfree(command); + return len; } - /* * Check permissions for SSL key files. */ -bool -check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart) -{ - int loglevel = isServerStart ? FATAL : LOG; - struct stat buf; - - if (stat(ssl_key_file, &buf) != 0) - { - ereport(loglevel, - (errcode_for_file_access(), - errmsg("could not access private key file \"%s\": %m", - ssl_key_file))); - return false; - } - - /* Key file must be a regular file */ - if (!S_ISREG(buf.st_mode)) - { - ereport(loglevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" is not a regular file", - ssl_key_file))); - return false; - } - - /* - * 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 roughly similar checks are performed in - * src/interfaces/libpq/fe-secure-openssl.c so any changes here may need - * to be made there as well. The environment is different though; this - * code can assume that we're not running as root. - * - * 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. - */ +bool check_ssl_key_file_permissions(const char *ssl_key_file, + bool isServerStart) { + int loglevel = isServerStart ? FATAL : LOG; + struct stat buf; + + if (stat(ssl_key_file, &buf) != 0) { + ereport(loglevel, (errcode_for_file_access(), + errmsg("could not access private key file \"%s\": %m", + ssl_key_file))); + return false; + } + + /* Key file must be a regular file */ + if (!S_ISREG(buf.st_mode)) { + ereport(loglevel, (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" is not a regular file", + ssl_key_file))); + return false; + } + + /* + * 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 roughly similar checks are performed in + * src/interfaces/libpq/fe-secure-openssl.c so any changes here may need + * to be made there as well. The environment is different though; this + * code can assume that we're not running as root. + * + * 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) - { - ereport(loglevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" must be owned by the database user or root", - ssl_key_file))); - return false; - } - - 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))) - { - ereport(loglevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" has group or world access", - ssl_key_file), - errdetail("File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root."))); - return false; - } + if (buf.st_uid != geteuid() && buf.st_uid != 0) { + ereport(loglevel, (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" must be owned by the " + "database user or root", + ssl_key_file))); + return false; + } + + 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))) { + ereport(loglevel, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" has group or world access", + ssl_key_file), + errdetail("File must have permissions u=rw (0600) or less if " + "owned by the database user, or permissions u=rw,g=r " + "(0640) or less if owned by root."))); + return false; + } #endif - return true; + return true; }