pgpass_0106.patch
text/x-patch
Filename: pgpass_0106.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| doc/src/sgml/libpq.sgml | 5 | 0 |
| doc/src/sgml/log-shipping.sgml | 15 | 0 |
| src/interfaces/libpq/fe-connect.c | 75 | 0 |
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 6024,6030 **** myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
<replaceable>hostname</replaceable>:<replaceable>port</replaceable>:<replaceable>database</replaceable>:<replaceable>username</replaceable>:<replaceable>password</replaceable>
</synopsis>
Each of the first four fields can be a literal value, or
! <literal>*</literal>, which matches anything. The password field from
the first line that matches the current connection parameters will be
used. (Therefore, put more-specific entries first when you are using
wildcards.) If an entry needs to contain <literal>:</literal> or
--- 6024,6031 ----
<replaceable>hostname</replaceable>:<replaceable>port</replaceable>:<replaceable>database</replaceable>:<replaceable>username</replaceable>:<replaceable>password</replaceable>
</synopsis>
Each of the first four fields can be a literal value, or
! <literal>*</literal>, which matches anything. Also <replaceable>database
! </replaceable> can be <literal>replication</literal>. The password field from
the first line that matches the current connection parameters will be
used. (Therefore, put more-specific entries first when you are using
wildcards.) If an entry needs to contain <literal>:</literal> or
***************
*** 6032,6038 **** myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
A host name of <literal>localhost</> matches both TCP (host name
<literal>localhost</>) and Unix domain socket (<literal>pghost</> empty
or the default socket directory) connections coming from the local
! machine.
</para>
<para>
--- 6033,6041 ----
A host name of <literal>localhost</> matches both TCP (host name
<literal>localhost</>) and Unix domain socket (<literal>pghost</> empty
or the default socket directory) connections coming from the local
! machine. Quoting one of the keywords <literal>*</literal> or
! <literal>replication</literal> makes the name lose its special character,
! and just matches each field with that name.
</para>
<para>
*** a/doc/src/sgml/log-shipping.sgml
--- b/doc/src/sgml/log-shipping.sgml
***************
*** 439,447 **** host replication foo 192.168.1.100/32 md5
</programlisting>
</para>
<para>
! The host name and port number of the primary, user name to connect as,
! and password are specified in the <filename>recovery.conf</> file or
! the corresponding environment variable on the standby.
For example, if the primary is running on host IP <literal>192.168.1.50</>,
port <literal>5432</literal>, the superuser's name for replication is
<literal>foo</>, and the password is <literal>foopass</>, the administrator
--- 439,449 ----
</programlisting>
</para>
<para>
! The host name and port number of the primary, and user name to connect as
! are specified in the <filename>recovery.conf</> file or the corresponding
! environment variable on the standby. The password can be supplied in the
! <filename>.pgpass</> file by using the <literal>replication</> keyword
! (see <xref linkend="libpq-pgpass">).
For example, if the primary is running on host IP <literal>192.168.1.50</>,
port <literal>5432</literal>, the superuser's name for replication is
<literal>foo</>, and the password is <literal>foopass</>, the administrator
***************
*** 449,456 **** host replication foo 192.168.1.100/32 md5
<programlisting>
# The standby connects to the primary that is running on host 192.168.1.50
! # and port 5432 as the user "foo" whose password is "foopass".
! primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
</programlisting>
</para>
</sect2>
--- 451,466 ----
<programlisting>
# The standby connects to the primary that is running on host 192.168.1.50
! # and port 5432 as the user "foo".
! primary_conninfo = 'host=192.168.1.50 port=5432 user=foo'
! </programlisting>
!
! In addition to that, the following line should be added to the
! <filename>.pgpass</> file on the standby so that it can connect to
! the primary without prompting for password.
!
! <programlisting>
! 192.168.1.50:5432:replication:foo:foopass
</programlisting>
</para>
</sect2>
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 83,88 **** static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
--- 83,90 ----
#define PGPASSFILE "pgpass.conf"
#endif
+ #define PWDFLINELEN NAMEDATALEN*5
+
/*
* Pre-8.5 servers will return this SQLSTATE if asked to set
* application_name in a startup packet. We hard-wire the value rather
***************
*** 273,280 **** static void defaultNoticeProcessor(void *arg, const char *message);
static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage);
static char *pwdfMatchesString(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
! char *username);
static void default_threadlock(int acquire);
--- 275,284 ----
static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage);
static char *pwdfMatchesString(char *buf, char *token);
+ static char *pwdfMatchesDbName(char *buf, char *token, bool replication);
+ static char *nextPwdfToken(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
! char *username, bool replication);
static void default_threadlock(int acquire);
***************
*** 516,522 **** connectOptions2(PGconn *conn)
if (conn->pgpass)
free(conn->pgpass);
conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
! conn->dbName, conn->pguser);
if (conn->pgpass == NULL)
conn->pgpass = strdup(DefaultPassword);
}
--- 520,527 ----
if (conn->pgpass)
free(conn->pgpass);
conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
! conn->dbName, conn->pguser,
! conn->replication);
if (conn->pgpass == NULL)
conn->pgpass = strdup(DefaultPassword);
}
***************
*** 3905,3960 **** defaultNoticeProcessor(void *arg, const char *message)
}
/*
! * returns a pointer to the next token or NULL if the current
* token doesn't match
*/
static char *
pwdfMatchesString(char *buf, char *token)
{
char *tbuf,
*ttok;
bool bslash = false;
if (buf == NULL || token == NULL)
return NULL;
tbuf = buf;
ttok = token;
! if (tbuf[0] == '*' && tbuf[1] == ':')
! return tbuf + 2;
! while (*tbuf != 0)
{
if (*tbuf == '\\' && !bslash)
{
tbuf++;
bslash = true;
}
! if (*tbuf == ':' && *ttok == 0 && !bslash)
! return tbuf + 1;
! bslash = false;
! if (*ttok == 0)
! return NULL;
! if (*tbuf == *ttok)
{
tbuf++;
! ttok++;
}
! else
! return NULL;
}
! return NULL;
}
/* Get a password from the password file. Return value is malloc'd. */
static char *
! PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
{
FILE *fp;
char pgpassfile[MAXPGPATH];
struct stat stat_buf;
char *passfile_env;
!
! #define LINELEN NAMEDATALEN*5
! char buf[LINELEN];
if (dbname == NULL || strlen(dbname) == 0)
return NULL;
--- 3910,4014 ----
}
/*
! * Returns a pointer to the next token or NULL if the current
* token doesn't match
*/
static char *
pwdfMatchesString(char *buf, char *token)
{
+ char pwdftok[PWDFLINELEN];
+
+ if (buf == NULL || token == NULL)
+ return NULL;
+ if ((buf = nextPwdfToken(buf, pwdftok)) == NULL)
+ return NULL;
+ if (strcmp(pwdftok, "*\n") == 0 ||
+ strcmp(pwdftok, token) == 0)
+ return buf;
+ return NULL;
+ }
+
+ /*
+ * Returns a pointer to the next token or NULL if the given
+ * database name doesn't match
+ */
+ static char *
+ pwdfMatchesDbName(char *buf, char *token, bool replication)
+ {
+ char pwdftok[PWDFLINELEN];
+
+ if (buf == NULL || token == NULL)
+ return NULL;
+ if ((buf = nextPwdfToken(buf, pwdftok)) == NULL)
+ return NULL;
+ if (strcmp(pwdftok, "*\n") == 0 ||
+ (strcmp(pwdftok, "replication\n") == 0 && replication) ||
+ strcmp(pwdftok, token) == 0)
+ return buf;
+ return NULL;
+ }
+
+ /*
+ * Grab one token out of 'buf'. Return a pointer to the next
+ * token or NULL if there is no token.
+ */
+ static char *
+ nextPwdfToken(char *buf, char *token)
+ {
char *tbuf,
*ttok;
bool bslash = false;
+ bool in_quote = false;
+ bool saw_quote = false;
if (buf == NULL || token == NULL)
return NULL;
tbuf = buf;
ttok = token;
! for (;;)
{
+ if (*tbuf == 0)
+ return NULL;
if (*tbuf == '\\' && !bslash)
{
tbuf++;
bslash = true;
}
! if (*tbuf == '"' && !bslash)
{
tbuf++;
! bslash = false;
! in_quote = !in_quote;
! saw_quote = true;
}
! if (*tbuf == ':' && !bslash && !in_quote)
! break;
! bslash = false;
! *ttok++ = *tbuf++;
}
!
! *ttok = '\0';
! if (!saw_quote &&
! (strcmp(token, "*") == 0 ||
! strcmp(token, "replication") == 0))
! {
! /* append newline to a magical keyword */
! *ttok++ = '\n';
! *ttok = '\0';
! }
! return tbuf + 1;
}
/* Get a password from the password file. Return value is malloc'd. */
static char *
! PasswordFromFile(char *hostname, char *port, char *dbname, char *username,
! bool replication)
{
FILE *fp;
char pgpassfile[MAXPGPATH];
struct stat stat_buf;
char *passfile_env;
! char buf[PWDFLINELEN];
if (dbname == NULL || strlen(dbname) == 0)
return NULL;
***************
*** 4040,4046 **** PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
if ((t = pwdfMatchesString(t, hostname)) == NULL ||
(t = pwdfMatchesString(t, port)) == NULL ||
! (t = pwdfMatchesString(t, dbname)) == NULL ||
(t = pwdfMatchesString(t, username)) == NULL)
continue;
ret = strdup(t);
--- 4094,4100 ----
if ((t = pwdfMatchesString(t, hostname)) == NULL ||
(t = pwdfMatchesString(t, port)) == NULL ||
! (t = pwdfMatchesDbName(t, dbname, replication)) == NULL ||
(t = pwdfMatchesString(t, username)) == NULL)
continue;
ret = strdup(t);
***************
*** 4050,4057 **** PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
fclose(fp);
return NULL;
-
- #undef LINELEN
}
/*
--- 4104,4109 ----