Skip to content

Commit c9b0cbe

Browse files
committed
Support having multiple Unix-domain sockets per postmaster.
Replace unix_socket_directory with unix_socket_directories, which is a list of socket directories, and adjust postmaster's code to allow zero or more Unix-domain sockets to be created. This is mostly a straightforward change, but since the Unix sockets ought to be created after the TCP/IP sockets for safety reasons (better chance of detecting a port number conflict), AddToDataDirLockFile needs to be fixed to support out-of-order updates of data directory lockfile lines. That's a change that had been foreseen to be necessary someday anyway. Honza Horak, reviewed and revised by Tom Lane
1 parent 85642ec commit c9b0cbe

File tree

17 files changed

+369
-126
lines changed

17 files changed

+369
-126
lines changed

doc/src/sgml/client-auth.sgml

+1-1
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ omicron bryanh guest1
838838
<varname>unix_socket_permissions</varname> (and possibly
839839
<varname>unix_socket_group</varname>) configuration parameters as
840840
described in <xref linkend="runtime-config-connection">. Or you
841-
could set the <varname>unix_socket_directory</varname>
841+
could set the <varname>unix_socket_directories</varname>
842842
configuration parameter to place the socket file in a suitably
843843
restricted directory.
844844
</para>

doc/src/sgml/config.sgml

+21-14
Original file line numberDiff line numberDiff line change
@@ -445,17 +445,24 @@ SET ENABLE_SEQSCAN TO OFF;
445445
</listitem>
446446
</varlistentry>
447447

448-
<varlistentry id="guc-unix-socket-directory" xreflabel="unix_socket_directory">
449-
<term><varname>unix_socket_directory</varname> (<type>string</type>)</term>
448+
<varlistentry id="guc-unix-socket-directories" xreflabel="unix_socket_directories">
449+
<term><varname>unix_socket_directories</varname> (<type>string</type>)</term>
450450
<indexterm>
451-
<primary><varname>unix_socket_directory</> configuration parameter</primary>
451+
<primary><varname>unix_socket_directories</> configuration parameter</primary>
452452
</indexterm>
453453
<listitem>
454454
<para>
455-
Specifies the directory of the Unix-domain socket on which the
456-
server is to listen for
457-
connections from client applications. The default is normally
458-
<filename>/tmp</filename>, but can be changed at build time.
455+
Specifies the directory of the Unix-domain socket(s) on which the
456+
server is to listen for connections from client applications.
457+
Multiple sockets can be created by listing multiple directories
458+
separated by commas. Whitespace between entries is
459+
ignored; surround a directory name with double quotes if you need
460+
to include whitespace or commas in the name.
461+
An empty value
462+
specifies not listening on any Unix-domain sockets, in which case
463+
only TCP/IP sockets can be used to connect to the server.
464+
The default value is normally
465+
<filename>/tmp</filename>, but that can be changed at build time.
459466
This parameter can only be set at server start.
460467
</para>
461468

@@ -464,8 +471,8 @@ SET ENABLE_SEQSCAN TO OFF;
464471
<literal>.s.PGSQL.<replaceable>nnnn</></literal> where
465472
<replaceable>nnnn</> is the server's port number, an ordinary file
466473
named <literal>.s.PGSQL.<replaceable>nnnn</>.lock</literal> will be
467-
created in the <varname>unix_socket_directory</> directory. Neither
468-
file should ever be removed manually.
474+
created in each of the <varname>unix_socket_directories</> directories.
475+
Neither file should ever be removed manually.
469476
</para>
470477

471478
<para>
@@ -482,8 +489,8 @@ SET ENABLE_SEQSCAN TO OFF;
482489
</indexterm>
483490
<listitem>
484491
<para>
485-
Sets the owning group of the Unix-domain socket. (The owning
486-
user of the socket is always the user that starts the
492+
Sets the owning group of the Unix-domain socket(s). (The owning
493+
user of the sockets is always the user that starts the
487494
server.) In combination with the parameter
488495
<varname>unix_socket_permissions</varname> this can be used as
489496
an additional access control mechanism for Unix-domain connections.
@@ -506,7 +513,7 @@ SET ENABLE_SEQSCAN TO OFF;
506513
</indexterm>
507514
<listitem>
508515
<para>
509-
Sets the access permissions of the Unix-domain socket. Unix-domain
516+
Sets the access permissions of the Unix-domain socket(s). Unix-domain
510517
sockets use the usual Unix file system permission set.
511518
The parameter value is expected to be a numeric mode
512519
specified in the format accepted by the
@@ -1852,7 +1859,7 @@ SET ENABLE_SEQSCAN TO OFF;
18521859
<varname>commit_delay</varname> behaved differently and was much
18531860
less effective: it affected only commits, rather than all WAL flushes,
18541861
and waited for the entire configured delay even if the WAL flush
1855-
was completed sooner. Beginning in <productname>PostgreSQL</> 9.3,
1862+
was completed sooner. Beginning in <productname>PostgreSQL</> 9.3,
18561863
the first process that becomes ready to flush waits for the configured
18571864
interval, while subsequent processes wait only until the leader
18581865
completes the flush. The default <varname>commit_delay</> is zero
@@ -6556,7 +6563,7 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
65566563
</row>
65576564
<row>
65586565
<entry><option>-k <replaceable>x</replaceable></option></entry>
6559-
<entry><literal>unix_socket_directory = <replaceable>x</replaceable></></entry>
6566+
<entry><literal>unix_socket_directories = <replaceable>x</replaceable></></entry>
65606567
</row>
65616568
<row>
65626569
<entry><option>-l</option></entry>

doc/src/sgml/ref/postgres-ref.sgml

+8-2
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,14 @@ PostgreSQL documentation
254254
<para>
255255
Specifies the directory of the Unix-domain socket on which
256256
<command>postgres</command> is to listen for
257-
connections from client applications. The default is normally
258-
<filename>/tmp</filename>, but can be changed at build time.
257+
connections from client applications. The value can also be a
258+
comma-separated list of directories. An empty value
259+
specifies not listening on any Unix-domain sockets, in which case
260+
only TCP/IP sockets can be used to connect to the server.
261+
The default value is normally
262+
<filename>/tmp</filename>, but that can be changed at build time.
263+
Specifying this option is equivalent to setting the <xref
264+
linkend="guc-unix-socket-directories"> configuration parameter.
259265
</para>
260266
</listitem>
261267
</varlistentry>

doc/src/sgml/runtime.sgml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
17181718
<para>
17191719
The simplest way to prevent spoofing for <literal>local</>
17201720
connections is to use a Unix domain socket directory (<xref
1721-
linkend="guc-unix-socket-directory">) that has write permission only
1721+
linkend="guc-unix-socket-directories">) that has write permission only
17221722
for a trusted local user. This prevents a malicious user from creating
17231723
their own socket file in that directory. If you are concerned that
17241724
some applications might still reference <filename>/tmp</> for the

src/backend/libpq/pqcomm.c

+61-31
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* StreamServerPort - Open postmaster's server port
4343
* StreamConnection - Create new connection with client
4444
* StreamClose - Close a client/backend connection
45-
* TouchSocketFile - Protect socket file against /tmp cleaners
45+
* TouchSocketFiles - Protect socket files against /tmp cleaners
4646
* pq_init - initialize libpq at backend startup
4747
* pq_comm_reset - reset libpq during error recovery
4848
* pq_close - shutdown libpq at backend exit
@@ -103,8 +103,8 @@ int Unix_socket_permissions;
103103
char *Unix_socket_group;
104104

105105

106-
/* Where the Unix socket file is */
107-
static char sock_path[MAXPGPATH];
106+
/* Where the Unix socket files are (list of palloc'd strings) */
107+
static List *sock_paths = NIL;
108108

109109

110110
/*
@@ -140,8 +140,8 @@ static int internal_flush(void);
140140
static void pq_set_nonblocking(bool nonblocking);
141141

142142
#ifdef HAVE_UNIX_SOCKETS
143-
static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
144-
static int Setup_AF_UNIX(void);
143+
static int Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath);
144+
static int Setup_AF_UNIX(char *sock_path);
145145
#endif /* HAVE_UNIX_SOCKETS */
146146

147147

@@ -234,29 +234,43 @@ pq_close(int code, Datum arg)
234234

235235
/* StreamDoUnlink()
236236
* Shutdown routine for backend connection
237-
* If a Unix socket is used for communication, explicitly close it.
237+
* If any Unix sockets are used for communication, explicitly close them.
238238
*/
239239
#ifdef HAVE_UNIX_SOCKETS
240240
static void
241241
StreamDoUnlink(int code, Datum arg)
242242
{
243-
Assert(sock_path[0]);
244-
unlink(sock_path);
243+
ListCell *l;
244+
245+
/* Loop through all created sockets... */
246+
foreach(l, sock_paths)
247+
{
248+
char *sock_path = (char *) lfirst(l);
249+
250+
unlink(sock_path);
251+
}
252+
/* Since we're about to exit, no need to reclaim storage */
253+
sock_paths = NIL;
245254
}
246255
#endif /* HAVE_UNIX_SOCKETS */
247256

248257
/*
249258
* StreamServerPort -- open a "listening" port to accept connections.
250259
*
251-
* Successfully opened sockets are added to the ListenSocket[] array,
252-
* at the first position that isn't PGINVALID_SOCKET.
260+
* family should be AF_UNIX or AF_UNSPEC; portNumber is the port number.
261+
* For AF_UNIX ports, hostName should be NULL and unixSocketDir must be
262+
* specified. For TCP ports, hostName is either NULL for all interfaces or
263+
* the interface to listen on, and unixSocketDir is ignored (can be NULL).
264+
*
265+
* Successfully opened sockets are added to the ListenSocket[] array (of
266+
* length MaxListen), at the first position that isn't PGINVALID_SOCKET.
253267
*
254268
* RETURNS: STATUS_OK or STATUS_ERROR
255269
*/
256270

257271
int
258272
StreamServerPort(int family, char *hostName, unsigned short portNumber,
259-
char *unixSocketName,
273+
char *unixSocketDir,
260274
pgsocket ListenSocket[], int MaxListen)
261275
{
262276
pgsocket fd;
@@ -273,6 +287,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
273287
int listen_index = 0;
274288
int added = 0;
275289

290+
#ifdef HAVE_UNIX_SOCKETS
291+
char unixSocketPath[MAXPGPATH];
292+
#endif
276293
#if !defined(WIN32) || defined(IPV6_V6ONLY)
277294
int one = 1;
278295
#endif
@@ -286,10 +303,14 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
286303
#ifdef HAVE_UNIX_SOCKETS
287304
if (family == AF_UNIX)
288305
{
289-
/* Lock_AF_UNIX will also fill in sock_path. */
290-
if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK)
306+
/*
307+
* Create unixSocketPath from portNumber and unixSocketDir and lock
308+
* that file path
309+
*/
310+
UNIXSOCK_PATH(unixSocketPath, portNumber, unixSocketDir);
311+
if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK)
291312
return STATUS_ERROR;
292-
service = sock_path;
313+
service = unixSocketPath;
293314
}
294315
else
295316
#endif /* HAVE_UNIX_SOCKETS */
@@ -432,7 +453,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
432453
(IS_AF_UNIX(addr->ai_family)) ?
433454
errhint("Is another postmaster already running on port %d?"
434455
" If not, remove socket file \"%s\" and retry.",
435-
(int) portNumber, sock_path) :
456+
(int) portNumber, service) :
436457
errhint("Is another postmaster already running on port %d?"
437458
" If not, wait a few seconds and retry.",
438459
(int) portNumber)));
@@ -443,7 +464,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
443464
#ifdef HAVE_UNIX_SOCKETS
444465
if (addr->ai_family == AF_UNIX)
445466
{
446-
if (Setup_AF_UNIX() != STATUS_OK)
467+
if (Setup_AF_UNIX(service) != STATUS_OK)
447468
{
448469
closesocket(fd);
449470
break;
@@ -490,10 +511,8 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
490511
* Lock_AF_UNIX -- configure unix socket file path
491512
*/
492513
static int
493-
Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
514+
Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath)
494515
{
495-
UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);
496-
497516
/*
498517
* Grab an interlock file associated with the socket file.
499518
*
@@ -502,13 +521,23 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
502521
* more portable, and second, it lets us remove any pre-existing socket
503522
* file without race conditions.
504523
*/
505-
CreateSocketLockFile(sock_path, true);
524+
CreateSocketLockFile(unixSocketPath, true, unixSocketDir);
506525

507526
/*
508527
* Once we have the interlock, we can safely delete any pre-existing
509528
* socket file to avoid failure at bind() time.
510529
*/
511-
unlink(sock_path);
530+
unlink(unixSocketPath);
531+
532+
/*
533+
* Arrange to unlink the socket file(s) at proc_exit. If this is the
534+
* first one, set up the on_proc_exit function to do it; then add this
535+
* socket file to the list of files to unlink.
536+
*/
537+
if (sock_paths == NIL)
538+
on_proc_exit(StreamDoUnlink, 0);
539+
540+
sock_paths = lappend(sock_paths, pstrdup(unixSocketPath));
512541

513542
return STATUS_OK;
514543
}
@@ -518,11 +547,8 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
518547
* Setup_AF_UNIX -- configure unix socket permissions
519548
*/
520549
static int
521-
Setup_AF_UNIX(void)
550+
Setup_AF_UNIX(char *sock_path)
522551
{
523-
/* Arrange to unlink the socket file at exit */
524-
on_proc_exit(StreamDoUnlink, 0);
525-
526552
/*
527553
* Fix socket ownership/permission if requested. Note we must do this
528554
* before we listen() to avoid a window where unwanted connections could
@@ -704,20 +730,24 @@ StreamClose(pgsocket sock)
704730
}
705731

706732
/*
707-
* TouchSocketFile -- mark socket file as recently accessed
733+
* TouchSocketFiles -- mark socket files as recently accessed
708734
*
709735
* This routine should be called every so often to ensure that the socket
710-
* file has a recent mod date (ordinary operations on sockets usually won't
711-
* change the mod date). That saves it from being removed by
736+
* files have a recent mod date (ordinary operations on sockets usually won't
737+
* change the mod date). That saves them from being removed by
712738
* overenthusiastic /tmp-directory-cleaner daemons. (Another reason we should
713739
* never have put the socket file in /tmp...)
714740
*/
715741
void
716-
TouchSocketFile(void)
742+
TouchSocketFiles(void)
717743
{
718-
/* Do nothing if we did not create a socket... */
719-
if (sock_path[0] != '\0')
744+
ListCell *l;
745+
746+
/* Loop through all created sockets... */
747+
foreach(l, sock_paths)
720748
{
749+
char *sock_path = (char *) lfirst(l);
750+
721751
/*
722752
* utime() is POSIX standard, utimes() is a common alternative. If we
723753
* have neither, there's no way to affect the mod or access time of

0 commit comments

Comments
 (0)