PostgreSQL currently requires the file mode mask (umask) to be 0077.
However, this precludes the possibility of a user in the postgres group
performing a backup (or whatever).  Now that
pg_start_backup()/pg_stop_backup() privileges can be delegated to an
unprivileged user, it makes sense to also allow a (relatively)
unprivileged user to perform the backup at the file system level as well.

This patch introduces a new initdb param, -u/-file-mode-mask, and a new
GUC, file_mode_mask, to allow the default mode of files and directories
in the $PGDATA directory to be modified.

This obviously required mode changes in a number of places, so at the
same time the BasicOpenFile(), OpenTransientFile(), and
PathNameOpenFile() have been split into versions that either use the
default permissions or allow custom permissions.  In the end there was
only one call to the custom permission version (be-fsstubs.c:505) for
all three variants.

The following three calls (at the least) need to be reviewed:

bin/pg_dump/pg_backup_directory.c:194
src/port/mkdtemp.c:190
bin/pg_basebackup.c:599:655:1399

And this call needs serious consideration:

bin/pg_rewind/file_ops.c:214

Besides that there should be tests to make sure the masks are working as
expected and these could be added to the initdb TAP tests, though no
mask tests exist at this time.  Making sure all file operations produce
the correct modes would need to be placed in a new module, perhaps the
new backup tests proposed in [1].

Adam Brightwell developed the patch based on an initial concept by me
and Stephen Frost.  I added the refactoring in fd.c and some additional
documentation.

This patch applies cleanly on 016c990 but may fare badly over time due
to the number of files modified.

-- 
-David
da...@pgmasters.net

[1]
https://www.postgresql.org/message-id/758e3fd1-45b4-5e28-75cd-e9e7f93a4...@pgmasters.net
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c 
b/contrib/pg_stat_statements/pg_stat_statements.c
index 62dec87..98f8170 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1858,8 +1858,7 @@ qtext_store(const char *query, int query_len,
        *query_offset = off;
 
        /* Now write the data into the successfully-reserved part of the file */
-       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
        if (fd < 0)
                goto error;
 
@@ -1923,7 +1922,7 @@ qtext_load_file(Size *buffer_size)
        int                     fd;
        struct stat stat;
 
-       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY);
        if (fd < 0)
        {
                if (errno != ENOENT)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 1b390a2..2371878 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -812,6 +812,38 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-file-mode-mask" xreflabel="file_mode_mask">
+      <term><varname>file_mode_mask</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>file_mode_mask</> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Sets the file mode mask (umask) for the data directory. The parameter
+        value is expected to be a numeric mode specified in the format
+        accepted by the <function>chmod</function> and
+        <function>umask</function> system calls. (To use the customary octal
+        format the number must start with a <literal>0</literal> (zero).)
+       </para>
+
+       <para>
+        The default <literal>file_mode_mask</literal> is 
<literal>0077</literal>,
+        meaning that the only the database owner can read and write files in
+        the data directory.  For example, setting the
+        <literal>file_mode_mask</literal> to <literal>0027</literal> would 
allow
+        any user in the same group as the database owner to read all database
+        files, which would be useful for producing a backup using a relatively
+        unprivileged user.
+       </para>
+
+       <para>
+        This parameter can only be set at server start.
+       </para>
+
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-bonjour" xreflabel="bonjour">
       <term><varname>bonjour</varname> (<type>boolean</type>)
       <indexterm>
diff --git a/src/backend/access/heap/rewriteheap.c 
b/src/backend/access/heap/rewriteheap.c
index c7b283c..53a2acc 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1010,8 +1010,7 @@ logical_rewrite_log_mapping(RewriteState state, 
TransactionId xid,
                src->off = 0;
                memcpy(src->path, path, sizeof(path));
                src->vfd = PathNameOpenFile(path,
-                                                                       O_CREAT 
| O_EXCL | O_WRONLY | PG_BINARY,
-                                                                       S_IRUSR 
| S_IWUSR);
+                                                                       O_CREAT 
| O_EXCL | O_WRONLY | PG_BINARY);
                if (src->vfd < 0)
                        ereport(ERROR,
                                        (errcode_for_file_access(),
@@ -1130,8 +1129,7 @@ heap_xlog_logical_rewrite(XLogReaderState *r)
                         xlrec->mapped_xid, XLogRecGetXid(r));
 
        fd = OpenTransientFile(path,
-                                                  O_CREAT | O_WRONLY | 
PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+                                                  O_CREAT | O_WRONLY | 
PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -1249,7 +1247,7 @@ CheckPointLogicalRewriteHeap(void)
                }
                else
                {
-                       int                     fd = OpenTransientFile(path, 
O_RDONLY | PG_BINARY, 0);
+                       int                     fd = OpenTransientFile(path, 
O_RDONLY | PG_BINARY);
 
                        /*
                         * The file cannot vanish due to concurrency since this 
function
diff --git a/src/backend/access/transam/slru.c 
b/src/backend/access/transam/slru.c
index a66ef5c..f385b79 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -594,7 +594,7 @@ SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
 
        SlruFileName(ctl, path, segno);
 
-       fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
        if (fd < 0)
        {
                /* expected: file doesn't exist */
@@ -649,7 +649,7 @@ SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno)
         * SlruPhysicalWritePage).  Hence, if we are InRecovery, allow the case
         * where the file doesn't exist, and return zeroes instead.
         */
-       fd = OpenTransientFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
        if (fd < 0)
        {
                if (errno != ENOENT || !InRecovery)
@@ -796,8 +796,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, 
SlruFlush fdata)
                 * don't use O_EXCL or O_TRUNC or anything like that.
                 */
                SlruFileName(ctl, path, segno);
-               fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY,
-                                                          S_IRUSR | S_IWUSR);
+               fd = OpenTransientFile(path, O_RDWR | O_CREAT | PG_BINARY);
                if (fd < 0)
                {
                        slru_errcause = SLRU_OPEN_FAILED;
diff --git a/src/backend/access/transam/timeline.c 
b/src/backend/access/transam/timeline.c
index 1fdc591..baa766a 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -306,8 +306,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID 
parentTLI,
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -324,7 +323,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID 
parentTLI,
        else
                TLHistoryFilePath(path, parentTLI);
 
-       srcfd = OpenTransientFile(path, O_RDONLY, 0);
+       srcfd = OpenTransientFile(path, O_RDONLY);
        if (srcfd < 0)
        {
                if (errno != ENOENT)
@@ -452,8 +451,7 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int 
size)
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/access/transam/twophase.c 
b/src/backend/access/transam/twophase.c
index 0a8edb9..1f02dd1 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1151,7 +1151,7 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings)
 
        TwoPhaseFilePath(path, xid);
 
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (fd < 0)
        {
                if (give_warnings)
@@ -1533,8 +1533,7 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, 
int len)
        TwoPhaseFilePath(path, xid);
 
        fd = OpenTransientFile(path,
-                                                  O_CREAT | O_TRUNC | O_WRONLY 
| PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+                                                  O_CREAT | O_TRUNC | O_WRONLY 
| PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/access/transam/xlog.c 
b/src/backend/access/transam/xlog.c
index 8973583..eed7dda 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -3156,8 +3156,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool 
use_lock)
         */
        if (*use_existent)
        {
-               fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method),
-                                                  S_IRUSR | S_IWUSR);
+               fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method));
                if (fd < 0)
                {
                        if (errno != ENOENT)
@@ -3182,8 +3181,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool 
use_lock)
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+       fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3275,8 +3273,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool 
use_lock)
        *use_existent = false;
 
        /* Now open original target segment (might not be file I just made) */
-       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
-                                          S_IRUSR | S_IWUSR);
+       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method));
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3317,7 +3314,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, 
XLogSegNo srcsegno,
         * Open the source file
         */
        XLogFilePath(path, srcTLI, srcsegno);
-       srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (srcfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3331,8 +3328,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, 
XLogSegNo srcsegno,
        unlink(tmppath);
 
        /* do not use get_sync_bit() here --- want to fsync only at end of fill 
*/
-       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -3504,8 +3500,7 @@ XLogFileOpen(XLogSegNo segno)
 
        XLogFilePath(path, ThisTimeLineID, segno);
 
-       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
-                                          S_IRUSR | S_IWUSR);
+       fd = BasicOpenFile(path, O_RDWR | PG_BINARY | 
get_sync_bit(sync_method));
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -3571,7 +3566,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
                snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
        }
 
-       fd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
        if (fd >= 0)
        {
                /* Success! */
@@ -4065,7 +4060,7 @@ ValidateXLOGDirectoryStructure(void)
        {
                ereport(LOG,
                                (errmsg("creating missing WAL directory 
\"%s\"", path)));
-               if (mkdir(path, S_IRWXU) < 0)
+               if (mkdir(path, PG_DEFAULT_DIR_MODE) < 0)
                        ereport(FATAL,
                                        (errmsg("could not create missing 
directory \"%s\": %m",
                                                        path)));
@@ -4404,8 +4399,7 @@ WriteControlFile(void)
        memcpy(buffer, ControlFile, sizeof(ControlFileData));
 
        fd = BasicOpenFile(XLOG_CONTROL_FILE,
-                                          O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+                                          O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY);
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -4444,8 +4438,7 @@ ReadControlFile(void)
         * Read data...
         */
        fd = BasicOpenFile(XLOG_CONTROL_FILE,
-                                          O_RDWR | PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+                                          O_RDWR | PG_BINARY);
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -4624,8 +4617,7 @@ UpdateControlFile(void)
        FIN_CRC32C(ControlFile->crc);
 
        fd = BasicOpenFile(XLOG_CONTROL_FILE,
-                                          O_RDWR | PG_BINARY,
-                                          S_IRUSR | S_IWUSR);
+                                          O_RDWR | PG_BINARY);
        if (fd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
diff --git a/src/backend/access/transam/xlogutils.c 
b/src/backend/access/transam/xlogutils.c
index 8b99b78..96ac73f 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -687,7 +687,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, 
Size count)
 
                        XLogFilePath(path, tli, sendSegNo);
 
-                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY);
 
                        if (sendFile < 0)
                        {
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 11ee536..578b46b 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -428,7 +428,7 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, 
char relpersistence)
 
                /* Check for existing file of same name */
                rpath = relpath(rnode, MAIN_FORKNUM);
-               fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0);
+               fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY);
 
                if (fd >= 0)
                {
diff --git a/src/backend/commands/tablespace.c 
b/src/backend/commands/tablespace.c
index f9c2620..312ac07 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -151,7 +151,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                        else
                        {
                                /* Directory creation failed? */
-                               if (mkdir(dir, S_IRWXU) < 0)
+                               if (mkdir(dir, PG_DEFAULT_DIR_MODE) < 0)
                                {
                                        char       *parentdir;
 
@@ -173,7 +173,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                                        get_parent_directory(parentdir);
                                        get_parent_directory(parentdir);
                                        /* Can't create parent and it doesn't 
already exist? */
-                                       if (mkdir(parentdir, S_IRWXU) < 0 && 
errno != EEXIST)
+                                       if (mkdir(parentdir, 
PG_DEFAULT_DIR_MODE) < 0 && errno != EEXIST)
                                                ereport(ERROR,
                                                                
(errcode_for_file_access(),
                                                          errmsg("could not 
create directory \"%s\": %m",
@@ -184,7 +184,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                                        parentdir = pstrdup(dir);
                                        get_parent_directory(parentdir);
                                        /* Can't create parent and it doesn't 
already exist? */
-                                       if (mkdir(parentdir, S_IRWXU) < 0 && 
errno != EEXIST)
+                                       if (mkdir(parentdir, 
PG_DEFAULT_DIR_MODE) < 0 && errno != EEXIST)
                                                ereport(ERROR,
                                                                
(errcode_for_file_access(),
                                                          errmsg("could not 
create directory \"%s\": %m",
@@ -192,7 +192,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool 
isRedo)
                                        pfree(parentdir);
 
                                        /* Create database directory */
-                                       if (mkdir(dir, S_IRWXU) < 0)
+                                       if (mkdir(dir, PG_DEFAULT_DIR_MODE) < 0)
                                                ereport(ERROR,
                                                                
(errcode_for_file_access(),
                                                          errmsg("could not 
create directory \"%s\": %m",
@@ -610,7 +610,7 @@ create_tablespace_directories(const char *location, const 
Oid tablespaceoid)
         * The creation of the version directory prevents more than one 
tablespace
         * in a single location.
         */
-       if (mkdir(location_with_version_dir, S_IRWXU) < 0)
+       if (mkdir(location_with_version_dir, PG_DEFAULT_DIR_MODE) < 0)
        {
                if (errno == EEXIST)
                        ereport(ERROR,
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index f537aff..c0c8d94 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -462,7 +462,7 @@ lo_import_internal(text *filename, Oid lobjOid)
         * open the file to be read in
         */
        text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
-       fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY, S_IRWXU);
+       fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -538,8 +538,8 @@ be_lo_export(PG_FUNCTION_ARGS)
         */
        text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
        oumask = umask(S_IWGRP | S_IWOTH);
-       fd = OpenTransientFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | 
PG_BINARY,
-                                                  S_IRUSR | S_IWUSR | S_IRGRP 
| S_IROTH);
+       fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | 
PG_BINARY,
+                                                          S_IRUSR | S_IWUSR | 
S_IRGRP | S_IROTH);
        umask(oumask);
        if (fd < 0)
                ereport(ERROR,
diff --git a/src/backend/postmaster/postmaster.c 
b/src/backend/postmaster/postmaster.c
index 271c492..bfb6c7d 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -579,9 +579,10 @@ PostmasterMain(int argc, char *argv[])
        IsPostmasterEnvironment = true;
 
        /*
-        * for security, no dir or file created can be group or other accessible
+        * Initially set most restrictive umask in case any files are
+        * accidentally created before file_mode_mask is loaded from GUC.
         */
-       umask(S_IRWXG | S_IRWXO);
+       umask(file_mode_mask);
 
        /*
         * Initialize random(3) so we don't get the same values in every run.
@@ -854,6 +855,9 @@ PostmasterMain(int argc, char *argv[])
                ExitPostmaster(0);
        }
 
+       /* Reset the file mode creation mask now that GUC has been loaded. */
+       umask(file_mode_mask);
+
        /* Verify that DataDir looks reasonable */
        checkDataDir();
 
@@ -1489,25 +1493,20 @@ checkDataDir(void)
 #endif
 
        /*
-        * Check if the directory has group or world access.  If so, reject.
-        *
-        * It would be possible to allow weaker constraints (for example, allow
-        * group access) but we cannot make a general assumption that that is
-        * okay; for example there are platforms where nearly all users
-        * customarily belong to the same group.  Perhaps this test should be
-        * configurable.
+        * Check if the directory has the correct permissions.  If not, then 
reject.
         *
         * 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.
         */
 #if !defined(WIN32) && !defined(__CYGWIN__)
-       if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+       if (stat_buf.st_mode & file_mode_mask)
                ereport(FATAL,
                                
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("data directory \"%s\" has group or 
world access",
+                                errmsg("data directory \"%s\" has incorrect 
permissions",
                                                DataDir),
-                                errdetail("Permissions should be u=rwx 
(0700).")));
+                                errdetail("Permissions should be (%04o).",
+                                               (PG_DEFAULT_DIR_MODE & 
~file_mode_mask))));
 #endif
 
        /* Look for PG_VERSION before looking for pg_control */
@@ -4393,7 +4392,7 @@ internal_forkexec(int argc, char *argv[], Port *port)
                 * As in OpenTemporaryFileInTablespace, try to make the 
temp-file
                 * directory
                 */
-               mkdir(PG_TEMP_FILES_DIR, S_IRWXU);
+               mkdir(PG_TEMP_FILES_DIR, PG_DEFAULT_DIR_MODE);
 
                fp = AllocateFile(tmpfilename, PG_BINARY_W);
                if (!fp)
diff --git a/src/backend/postmaster/syslogger.c 
b/src/backend/postmaster/syslogger.c
index 13a0301..684944d 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -41,6 +41,7 @@
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
 #include "storage/dsm.h"
+#include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/pg_shmem.h"
@@ -320,7 +321,7 @@ SysLoggerMain(int argc, char *argv[])
                                /*
                                 * Also, create new directory if not present; 
ignore errors
                                 */
-                               mkdir(Log_directory, S_IRWXU);
+                               mkdir(Log_directory, PG_DEFAULT_DIR_MODE);
                        }
                        if (strcmp(Log_filename, currentLogFilename) != 0)
                        {
@@ -555,7 +556,7 @@ SysLogger_Start(void)
        /*
         * Create log directory if not present; ignore errors
         */
-       mkdir(Log_directory, S_IRWXU);
+       mkdir(Log_directory, PG_DEFAULT_DIR_MODE);
 
        /*
         * The initial logfile is created right in the postmaster, to verify 
that
diff --git a/src/backend/replication/logical/origin.c 
b/src/backend/replication/logical/origin.c
index bf84c68..51d54ab 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -527,8 +527,7 @@ CheckPointReplicationOrigin(void)
         * CheckpointLock.
         */
        tmpfd = OpenTransientFile((char *) tmppath,
-                                                         O_CREAT | O_EXCL | 
O_WRONLY | PG_BINARY,
-                                                         S_IRUSR | S_IWUSR);
+                                                         O_CREAT | O_EXCL | 
O_WRONLY | PG_BINARY);
        if (tmpfd < 0)
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -637,7 +636,7 @@ StartupReplicationOrigin(void)
 
        elog(DEBUG2, "starting up replication origin progress state");
 
-       fd = OpenTransientFile((char *) path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile((char *) path, O_RDONLY | PG_BINARY);
 
        /*
         * might have had max_replication_slots == 0 last run, or we just 
brought
diff --git a/src/backend/replication/logical/reorderbuffer.c 
b/src/backend/replication/logical/reorderbuffer.c
index 8aac670..af7edea 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2103,8 +2103,7 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, 
ReorderBufferTXN *txn)
 
                        /* open segment, create it if necessary */
                        fd = OpenTransientFile(path,
-                                                                  O_CREAT | 
O_WRONLY | O_APPEND | PG_BINARY,
-                                                                  S_IRUSR | 
S_IWUSR);
+                                                                  O_CREAT | 
O_WRONLY | O_APPEND | PG_BINARY);
 
                        if (fd < 0)
                                ereport(ERROR,
@@ -2345,7 +2344,7 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, 
ReorderBufferTXN *txn,
                                        NameStr(MyReplicationSlot->data.name), 
txn->xid,
                                        (uint32) (recptr >> 32), (uint32) 
recptr);
 
-                       *fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+                       *fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
                        if (*fd < 0 && errno == ENOENT)
                        {
                                *fd = -1;
@@ -3030,7 +3029,7 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, 
const char *fname)
        LogicalRewriteMappingData map;
 
        sprintf(path, "pg_logical/mappings/%s", fname);
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/replication/logical/snapbuild.c 
b/src/backend/replication/logical/snapbuild.c
index 6f19cdc..961b0f9 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1574,8 +1574,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 
        /* we have valid data now, open tempfile and write it there */
        fd = OpenTransientFile(tmppath,
-                                                  O_CREAT | O_EXCL | O_WRONLY 
| PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+                                                  O_CREAT | O_EXCL | O_WRONLY 
| PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errmsg("could not open file \"%s\": %m", 
path)));
@@ -1655,7 +1654,7 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
        sprintf(path, "pg_logical/snapshots/%X-%X.snap",
                        (uint32) (lsn >> 32), (uint32) lsn);
 
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
 
        if (fd < 0 && errno == ENOENT)
                return false;
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 10d69d0..7e8b50e 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1011,7 +1011,7 @@ CreateSlotOnDisk(ReplicationSlot *slot)
                rmtree(tmppath, true);
 
        /* Create and fsync the temporary slot directory. */
-       if (mkdir(tmppath, S_IRWXU) < 0)
+       if (mkdir(tmppath, PG_DEFAULT_DIR_MODE) < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not create directory \"%s\": %m",
@@ -1072,9 +1072,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, 
int elevel)
        sprintf(tmppath, "%s/state.tmp", dir);
        sprintf(path, "%s/state", dir);
 
-       fd = OpenTransientFile(tmppath,
-                                                  O_CREAT | O_EXCL | O_WRONLY 
| PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(tmppath, O_CREAT | O_EXCL | O_WRONLY | 
PG_BINARY);
        if (fd < 0)
        {
                ereport(elevel,
@@ -1187,7 +1185,7 @@ RestoreSlotFromDisk(const char *name)
 
        elog(DEBUG1, "restoring replication slot from \"%s\"", path);
 
-       fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
+       fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
 
        /*
         * We do not need to handle this as we are rename()ing the directory 
into
diff --git a/src/backend/replication/walsender.c 
b/src/backend/replication/walsender.c
index 9cf9eb0..e1af7a3 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -437,7 +437,7 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd)
        pq_sendint(&buf, len, 4);       /* col1 len */
        pq_sendbytes(&buf, histfname, len);
 
-       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0666);
+       fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -2031,7 +2031,7 @@ retry:
 
                        XLogFilePath(path, curFileTimeLine, sendSegNo);
 
-                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+                       sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY);
                        if (sendFile < 0)
                        {
                                /*
diff --git a/src/backend/storage/file/copydir.c 
b/src/backend/storage/file/copydir.c
index 101da47..0e078f5 100644
--- a/src/backend/storage/file/copydir.c
+++ b/src/backend/storage/file/copydir.c
@@ -41,7 +41,7 @@ copydir(char *fromdir, char *todir, bool recurse)
        char            fromfile[MAXPGPATH];
        char            tofile[MAXPGPATH];
 
-       if (mkdir(todir, S_IRWXU) != 0)
+       if (mkdir(todir, PG_DEFAULT_DIR_MODE) != 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not create directory \"%s\": 
%m", todir)));
@@ -148,14 +148,13 @@ copy_file(char *fromfile, char *tofile)
        /*
         * Open the files
         */
-       srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY, 0);
+       srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
        if (srcfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\": %m", 
fromfile)));
 
-       dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-                                                         S_IRUSR | S_IWUSR);
+       dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY);
        if (dstfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index fd02fc0..46caf90 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -138,6 +138,8 @@ int                 max_files_per_process = 1000;
  */
 int                    max_safe_fds = 32;      /* default if not changed */
 
+/* The file mode creation mask for creating new files and directories. */
+int                    file_mode_mask = PG_DEFAULT_MODE_MASK;
 
 /* Debugging.... */
 
@@ -604,7 +606,7 @@ durable_rename(const char *oldfile, const char *newfile, 
int elevel)
        if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
                return -1;
 
-       fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR, 0);
+       fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR);
        if (fd < 0)
        {
                if (errno != ENOENT)
@@ -896,7 +898,7 @@ set_max_safe_fds(void)
  * this module wouldn't have any open files to close at that point anyway.
  */
 int
-BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
+BasicOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
 {
        int                     fd;
 
@@ -922,6 +924,12 @@ tryAgain:
        return -1;                                      /* failure */
 }
 
+int
+BasicOpenFile(FileName fileName, int fileFlags)
+{
+       return BasicOpenFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE);
+}
+
 #if defined(FDDEBUG)
 
 static void
@@ -1047,8 +1055,8 @@ LruInsert(File file)
                 * overall system file table being full.  So, be prepared to 
release
                 * another FD if necessary...
                 */
-               vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags,
-                                                                
vfdP->fileMode);
+               vfdP->fd = BasicOpenFilePerm(vfdP->fileName, vfdP->fileFlags,
+                                                                        
vfdP->fileMode);
                if (vfdP->fd < 0)
                {
                        DO_DB(elog(LOG, "re-open failed: %m"));
@@ -1263,13 +1271,19 @@ FileInvalidate(File file)
  * (which should always be $PGDATA when this code is running).
  */
 File
-PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
+PathNameOpenFile(FileName fileName, int fileFlags)
+{
+       return PathNameOpenFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE);
+}
+
+File
+PathNameOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
 {
        char       *fnamecopy;
        File            file;
        Vfd                *vfdP;
 
-       DO_DB(elog(LOG, "PathNameOpenFile: %s %x %o",
+       DO_DB(elog(LOG, "PathNameOpenFilePerm: %s %x %o",
                           fileName, fileFlags, fileMode));
 
        /*
@@ -1287,7 +1301,7 @@ PathNameOpenFile(FileName fileName, int fileFlags, int 
fileMode)
        /* Close excess kernel FDs. */
        ReleaseLruFiles();
 
-       vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode);
+       vfdP->fd = BasicOpenFilePerm(fileName, fileFlags, fileMode);
 
        if (vfdP->fd < 0)
        {
@@ -1424,8 +1438,7 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool 
rejectError)
         * temp file that can be reused.
         */
        file = PathNameOpenFile(tempfilepath,
-                                                       O_RDWR | O_CREAT | 
O_TRUNC | PG_BINARY,
-                                                       0600);
+                                                       O_RDWR | O_CREAT | 
O_TRUNC | PG_BINARY);
        if (file <= 0)
        {
                /*
@@ -1436,11 +1449,10 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool 
rejectError)
                 * just did the same thing.  If it doesn't work then we'll bomb 
out on
                 * the second create attempt, instead.
                 */
-               mkdir(tempdirpath, S_IRWXU);
+               mkdir(tempdirpath, PG_DEFAULT_DIR_MODE);
 
                file = PathNameOpenFile(tempfilepath,
-                                                               O_RDWR | 
O_CREAT | O_TRUNC | PG_BINARY,
-                                                               0600);
+                                                               O_RDWR | 
O_CREAT | O_TRUNC | PG_BINARY);
                if (file <= 0 && rejectError)
                        elog(ERROR, "could not create temporary file \"%s\": 
%m",
                                 tempfilepath);
@@ -2090,7 +2102,7 @@ TryAgain:
  * Like AllocateFile, but returns an unbuffered fd like open(2)
  */
 int
-OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
+OpenTransientFilePerm(FileName fileName, int fileFlags, int fileMode)
 {
        int                     fd;
 
@@ -2107,7 +2119,7 @@ OpenTransientFile(FileName fileName, int fileFlags, int 
fileMode)
        /* Close excess kernel FDs. */
        ReleaseLruFiles();
 
-       fd = BasicOpenFile(fileName, fileFlags, fileMode);
+       fd = BasicOpenFilePerm(fileName, fileFlags, fileMode);
 
        if (fd >= 0)
        {
@@ -2124,6 +2136,12 @@ OpenTransientFile(FileName fileName, int fileFlags, int 
fileMode)
        return -1;                                      /* failure */
 }
 
+int
+OpenTransientFile(FileName fileName, int fileFlags)
+{
+       return OpenTransientFilePerm(fileName, fileFlags, PG_DEFAULT_FILE_MODE);
+}
+
 /*
  * Routines that want to initiate a pipe stream should use OpenPipeStream
  * rather than plain popen().  This lets fd.c deal with freeing FDs if
@@ -3030,7 +3048,7 @@ pre_sync_fname(const char *fname, bool isdir, int elevel)
        if (isdir)
                return;
 
-       fd = OpenTransientFile((char *) fname, O_RDONLY | PG_BINARY, 0);
+       fd = OpenTransientFile((char *) fname, O_RDONLY | PG_BINARY);
 
        if (fd < 0)
        {
@@ -3090,7 +3108,7 @@ fsync_fname_ext(const char *fname, bool isdir, bool 
ignore_perm, int elevel)
        else
                flags |= O_RDONLY;
 
-       fd = OpenTransientFile((char *) fname, flags, 0);
+       fd = OpenTransientFile((char *) fname, flags);
 
        /*
         * Some OSs don't allow us to open directories at all (Windows returns
diff --git a/src/backend/storage/ipc/dsm_impl.c 
b/src/backend/storage/ipc/dsm_impl.c
index b2c9cdc..80ee4fa 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -283,7 +283,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size 
request_size,
         * returning.
         */
        flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
-       if ((fd = shm_open(name, flags, 0600)) == -1)
+       if ((fd = shm_open(name, flags, PG_DEFAULT_FILE_MODE)) == -1)
        {
                if (errno != EEXIST)
                        ereport(elevel,
@@ -834,7 +834,7 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size 
request_size,
 
        /* Create new segment or open an existing one for attach or resize. */
        flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
-       if ((fd = OpenTransientFile(name, flags, 0600)) == -1)
+       if ((fd = OpenTransientFile(name, flags)) == -1)
        {
                if (errno != EEXIST)
                        ereport(elevel,
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index ffd91f5..dfc5b75 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -28,6 +28,7 @@
 #include "postmaster/autovacuum.h"
 #endif
 #include "storage/dsm.h"
+#include "storage/fd.h"
 #include "storage/ipc.h"
 #include "tcop/tcopprot.h"
 
@@ -132,8 +133,8 @@ proc_exit(int code)
                else
                        snprintf(gprofDirName, 32, "gprof/%d", (int) getpid());
 
-               mkdir("gprof", S_IRWXU | S_IRWXG | S_IRWXO);
-               mkdir(gprofDirName, S_IRWXU | S_IRWXG | S_IRWXO);
+               mkdir("gprof", PG_DEFAULT_DIR_MODE);
+               mkdir(gprofDirName, PG_DEFAULT_DIR_MODE);
                chdir(gprofDirName);
        }
 #endif
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 6c17b54..cf951a2 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -303,7 +303,7 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
 
        path = relpath(reln->smgr_rnode, forkNum);
 
-       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 
0600);
+       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
 
        if (fd < 0)
        {
@@ -316,7 +316,7 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
                 * already, even if isRedo is not set.  (See also mdopen)
                 */
                if (isRedo || IsBootstrapProcessingMode())
-                       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
+                       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY);
                if (fd < 0)
                {
                        /* be sure to report the error reported by create, not 
open */
@@ -429,7 +429,7 @@ mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, 
bool isRedo)
                /* truncate(2) would be easier here, but Windows hasn't got it 
*/
                int                     fd;
 
-               fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
+               fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
                if (fd >= 0)
                {
                        int                     save_errno;
@@ -582,7 +582,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
 
        path = relpath(reln->smgr_rnode, forknum);
 
-       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
+       fd = PathNameOpenFile(path, O_RDWR | PG_BINARY);
 
        if (fd < 0)
        {
@@ -593,7 +593,7 @@ mdopen(SMgrRelation reln, ForkNumber forknum, int behavior)
                 * substitute for mdcreate() in bootstrap mode only. (See 
mdcreate)
                 */
                if (IsBootstrapProcessingMode())
-                       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY, 0600);
+                       fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | 
PG_BINARY);
                if (fd < 0)
                {
                        if ((behavior & EXTENSION_RETURN_NULL) &&
@@ -1779,7 +1779,7 @@ _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, 
BlockNumber segno,
        fullpath = _mdfd_segpath(reln, forknum, segno);
 
        /* open the file */
-       fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags, 0600);
+       fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags);
 
        pfree(fullpath);
 
diff --git a/src/backend/utils/cache/relmapper.c 
b/src/backend/utils/cache/relmapper.c
index c9d6e44..fe68b5b 100644
--- a/src/backend/utils/cache/relmapper.c
+++ b/src/backend/utils/cache/relmapper.c
@@ -643,8 +643,7 @@ load_relmap_file(bool shared)
        }
 
        /* Read data ... */
-       fd = OpenTransientFile(mapfilename,
-                                                  O_RDONLY | PG_BINARY, 
S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(mapfilename, O_RDONLY | PG_BINARY);
        if (fd < 0)
                ereport(FATAL,
                                (errcode_for_file_access(),
@@ -742,9 +741,7 @@ write_relmap_file(bool shared, RelMapFile *newmap,
                realmap = &local_map;
        }
 
-       fd = OpenTransientFile(mapfilename,
-                                                  O_WRONLY | O_CREAT | 
PG_BINARY,
-                                                  S_IRUSR | S_IWUSR);
+       fd = OpenTransientFile(mapfilename, O_WRONLY | O_CREAT | PG_BINARY);
        if (fd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0707f66..bb3e471 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -190,6 +190,7 @@ static void assign_application_name(const char *newval, 
void *extra);
 static bool check_cluster_name(char **newval, void **extra, GucSource source);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static const char *show_file_mode_mask(void);
 
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
@@ -2841,6 +2842,18 @@ static struct config_int ConfigureNamesInt[] =
                4096, 64, MAX_KILOBYTES,
                NULL, NULL, NULL
        },
+       {
+               {"file_mode_mask", PGC_POSTMASTER, UNGROUPED,
+                       gettext_noop("Sets the file mode creation mask for the 
backend process."),
+                       gettext_noop("The parameter value is expected to be a 
numeric mode"
+                                                "specification in the form 
accepted by the chmod and "
+                                                "umask system calls.  (To use 
the customary octal "
+                                                "format the number must start 
with a 0 (zero).)")
+               },
+               &file_mode_mask,
+               PG_DEFAULT_MODE_MASK, 0000, 0777,
+               NULL, NULL, show_file_mode_mask
+       },
 
        /* End-of-list marker */
        {
@@ -7186,8 +7199,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
         * truncate and reuse it.
         */
        Tmpfd = BasicOpenFile(AutoConfTmpFileName,
-                                                 O_CREAT | O_RDWR | O_TRUNC,
-                                                 S_IRUSR | S_IWUSR);
+                                                 O_CREAT | O_RDWR | O_TRUNC);
        if (Tmpfd < 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
@@ -10444,6 +10456,15 @@ show_unix_socket_permissions(void)
 }
 
 static const char *
+show_file_mode_mask(void)
+{
+       static char buf[8];
+
+       snprintf(buf, sizeof(buf), "%04o", file_mode_mask);
+       return buf;
+}
+
+static const char *
 show_log_file_mode(void)
 {
        static char buf[8];
diff --git a/src/backend/utils/misc/postgresql.conf.sample 
b/src/backend/utils/misc/postgresql.conf.sample
index 157d775..81fd9da 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -49,6 +49,7 @@
 #external_pid_file = ''                        # write an extra PID file
                                        # (change requires restart)
 
+#file_mode_mask = 0077
 
 #------------------------------------------------------------------------------
 # CONNECTIONS AND AUTHENTICATION
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 1ed0d20..283ec09 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -110,6 +110,15 @@ static const char *const auth_methods_local[] = {
        NULL
 };
 
+/* File mode to use with chmod on files. */
+#define PG_DEFAULT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH 
| S_IWOTH)
+
+/* File mode to use with chmod on directories. */
+#define PG_DEFAULT_DIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
+
+/* Default file mode creation mask. */
+#define PG_DEFAULT_MODE_MASK (S_IRWXG | S_IRWXO)
+
 /*
  * these values are passed in by makefile defines
  */
@@ -139,6 +148,7 @@ static bool sync_only = false;
 static bool show_setting = false;
 static bool data_checksums = false;
 static char *xlog_dir = "";
+static mode_t file_mode_mask = PG_DEFAULT_MODE_MASK;
 
 
 /* internal vars */
@@ -1095,6 +1105,11 @@ setup_config(void)
        conflines = replace_token(conflines, "#dynamic_shared_memory_type = 
posix",
                                                          repltok);
 
+       snprintf(repltok, sizeof(repltok), "file_mode_mask = %04o",
+                        file_mode_mask);
+       conflines = replace_token(conflines, "#file_mode_mask = 0077",
+                                                         repltok);
+
 #if DEFAULT_BACKEND_FLUSH_AFTER > 0
        snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB",
                         DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024));
@@ -1131,7 +1146,7 @@ setup_config(void)
        snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
 
        writefile(path, conflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -1151,7 +1166,7 @@ setup_config(void)
        sprintf(path, "%s/postgresql.auto.conf", pg_data);
 
        writefile(path, autoconflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -1235,7 +1250,7 @@ setup_config(void)
        snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
 
        writefile(path, conflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -1251,7 +1266,7 @@ setup_config(void)
        snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
 
        writefile(path, conflines);
-       if (chmod(path, S_IRUSR | S_IWUSR) != 0)
+       if (chmod(path, (PG_DEFAULT_FILE_MODE & ~file_mode_mask)) != 0)
        {
                fprintf(stderr, _("%s: could not change permissions of \"%s\": 
%s\n"),
                                progname, path, strerror(errno));
@@ -2243,6 +2258,7 @@ usage(const char *progname)
        printf(_("      --auth-local=METHOD   default authentication method for 
local-socket connections\n"));
        printf(_(" [-D, --pgdata=]DATADIR     location for this database 
cluster\n"));
        printf(_("  -E, --encoding=ENCODING   set default encoding for new 
databases\n"));
+       printf(_("  -u, --file-mode-mask=MASK set default file mode creation 
mask (umask)\n"));
        printf(_("      --locale=LOCALE       set default locale for new 
databases\n"));
        printf(_("      --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n"
                         "      --lc-monetary=, --lc-numeric=, 
--lc-time=LOCALE\n"
@@ -2624,7 +2640,7 @@ create_data_directory(void)
                                   pg_data);
                        fflush(stdout);
 
-                       if (pg_mkdir_p(pg_data, S_IRWXU) != 0)
+                       if (pg_mkdir_p(pg_data, PG_DEFAULT_DIR_MODE) != 0)
                        {
                                fprintf(stderr, _("%s: could not create 
directory \"%s\": %s\n"),
                                                progname, pg_data, 
strerror(errno));
@@ -2642,7 +2658,7 @@ create_data_directory(void)
                                   pg_data);
                        fflush(stdout);
 
-                       if (chmod(pg_data, S_IRWXU) != 0)
+                       if (chmod(pg_data, (PG_DEFAULT_DIR_MODE & 
~file_mode_mask)) != 0)
                        {
                                fprintf(stderr, _("%s: could not change 
permissions of directory \"%s\": %s\n"),
                                                progname, pg_data, 
strerror(errno));
@@ -2710,7 +2726,8 @@ create_xlog_or_symlink(void)
                                           xlog_dir);
                                fflush(stdout);
 
-                               if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0)
+                               printf("MASK: %04o\n", file_mode_mask);
+                               if (pg_mkdir_p(xlog_dir, PG_DEFAULT_DIR_MODE) 
!= 0)
                                {
                                        fprintf(stderr, _("%s: could not create 
directory \"%s\": %s\n"),
                                                        progname, xlog_dir, 
strerror(errno));
@@ -2728,7 +2745,8 @@ create_xlog_or_symlink(void)
                                           xlog_dir);
                                fflush(stdout);
 
-                               if (chmod(xlog_dir, S_IRWXU) != 0)
+                               printf("MASK: %04o\n", file_mode_mask);
+                               if (chmod(xlog_dir, (PG_DEFAULT_DIR_MODE & 
~file_mode_mask)) != 0)
                                {
                                        fprintf(stderr, _("%s: could not change 
permissions of directory \"%s\": %s\n"),
                                                        progname, xlog_dir, 
strerror(errno));
@@ -2778,7 +2796,7 @@ create_xlog_or_symlink(void)
        else
        {
                /* Without -X option, just make the subdirectory normally */
-               if (mkdir(subdirloc, S_IRWXU) < 0)
+               if (mkdir(subdirloc, PG_DEFAULT_DIR_MODE) < 0)
                {
                        fprintf(stderr, _("%s: could not create directory 
\"%s\": %s\n"),
                                        progname, subdirloc, strerror(errno));
@@ -2814,7 +2832,9 @@ initialize_data_directory(void)
 
        setup_signals();
 
-       umask(S_IRWXG | S_IRWXO);
+       /* Set the file mode creation mask. */
+       umask(file_mode_mask);
+       printf(_("Initializing with file mode creation mask: %04o\n"), 
file_mode_mask);
 
        create_data_directory();
 
@@ -2834,7 +2854,7 @@ initialize_data_directory(void)
                 * The parent directory already exists, so we only need mkdir() 
not
                 * pg_mkdir_p() here, which avoids some failure modes; cf bug 
#13853.
                 */
-               if (mkdir(path, S_IRWXU) < 0)
+               if (mkdir(path, PG_DEFAULT_DIR_MODE) < 0)
                {
                        fprintf(stderr, _("%s: could not create directory 
\"%s\": %s\n"),
                                        progname, path, strerror(errno));
@@ -2942,6 +2962,7 @@ main(int argc, char *argv[])
                {"sync-only", no_argument, NULL, 'S'},
                {"waldir", required_argument, NULL, 'X'},
                {"data-checksums", no_argument, NULL, 'k'},
+               {"file-mode-mask", required_argument, NULL, 'u'},
                {NULL, 0, NULL, 0}
        };
 
@@ -2983,7 +3004,7 @@ main(int argc, char *argv[])
 
        /* process command-line options */
 
-       while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", 
long_options, &option_index)) != -1)
+       while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:u:", 
long_options, &option_index)) != -1)
        {
                switch (c)
                {
@@ -3074,6 +3095,9 @@ main(int argc, char *argv[])
                        case 'X':
                                xlog_dir = pg_strdup(optarg);
                                break;
+                       case 'u':
+                               file_mode_mask = strtoul(optarg, NULL, 8);
+                               break;
                        default:
                                /* getopt_long already emitted a complaint */
                                fprintf(stderr, _("Try \"%s --help\" for more 
information.\n"),
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index 1a43a2c..6660b7b 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -22,7 +22,7 @@
  * Use them for all file activity...
  *
  *     File fd;
- *     fd = PathNameOpenFile("foo", O_RDONLY, 0600);
+ *     fd = PathNameOpenFile("foo", O_RDONLY);
  *
  *     AllocateFile();
  *     FreeFile();
@@ -59,13 +59,21 @@ extern int  max_files_per_process;
  */
 extern int     max_safe_fds;
 
+/* The file mode creation mask for creating new files and directories. */
+extern int     file_mode_mask;
+
+/* Define default modes and masks. */
+#define PG_DEFAULT_FILE_MODE   (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 
S_IROTH | S_IWOTH)
+#define PG_DEFAULT_DIR_MODE            (S_IRWXU | S_IRWXG | S_IRWXO)
+#define PG_DEFAULT_MODE_MASK   (S_IRWXG | S_IRWXO)
 
 /*
  * prototypes for functions in fd.c
  */
 
 /* Operations on virtual Files --- equivalent to Unix kernel file ops */
-extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode);
+extern File PathNameOpenFilePerm(FileName fileName, int fileFlags, int 
fileMode);
+extern File PathNameOpenFile(FileName fileName, int fileFlags);
 extern File OpenTemporaryFile(bool interXact);
 extern void FileClose(File file);
 extern int     FilePrefetch(File file, off_t offset, int amount);
@@ -94,11 +102,13 @@ extern struct dirent *ReadDir(DIR *dir, const char 
*dirname);
 extern int     FreeDir(DIR *dir);
 
 /* Operations to allow use of a plain kernel FD, with automatic cleanup */
-extern int     OpenTransientFile(FileName fileName, int fileFlags, int 
fileMode);
+extern int     OpenTransientFilePerm(FileName fileName, int fileFlags, int 
fileMode);
+extern int OpenTransientFile(FileName fileName, int fileFlags);
 extern int     CloseTransientFile(int fd);
 
 /* If you've really really gotta have a plain kernel FD, use this */
-extern int     BasicOpenFile(FileName fileName, int fileFlags, int fileMode);
+extern int     BasicOpenFilePerm(FileName fileName, int fileFlags, int 
fileMode);
+extern int     BasicOpenFile(FileName fileName, int fileFlags);
 
 /* Miscellaneous support routines */
 extern void InitFileAccess(void);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to