Fix failures to ignore \r when reading Windows-style newlines.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 25 Jul 2019 16:10:55 +0000 (12:10 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 25 Jul 2019 16:11:19 +0000 (12:11 -0400)
libpq failed to ignore Windows-style newlines in connection service files.
This normally wasn't a problem on Windows itself, because fgets() would
convert \r\n to just \n.  But if libpq were running inside a program that
changes the default fopen mode to binary, it would see the \r's and think
they were data.  In any case, it's project policy to ignore \r in text
files unconditionally, because people sometimes try to use files with
DOS-style newlines on Unix machines, where the C library won't hide that
from us.

Hence, adjust parseServiceFile() to ignore \r as well as \n at the end of
the line.  In HEAD, go a little further and make it ignore all trailing
whitespace, to match what it's always done with leading whitespace.

In HEAD, also run around and fix up everyplace where we have
newline-chomping code to make all those places look consistent and
uniformly drop \r.  It is not clear whether any of those changes are
fixing live bugs.  Most of the non-cosmetic changes are in places that
are reading popen output, and the jury is still out as to whether popen
on Windows can return \r\n.  (The Windows-specific code in pipe_read_line
seems to think so, but our lack of support for this elsewhere suggests
maybe it's not a problem in practice.)  Hence, I desisted from applying
those changes to back branches, except in run_ssl_passphrase_command()
which is new enough and little-tested enough that we'd probably not have
heard about any problems there.

Tom Lane and Michael Paquier, per bug #15827 from Jorge Gustavo Rocha.
Back-patch the parseServiceFile() change to all supported branches,
and the run_ssl_passphrase_command() change to v11 where that was added.

Discussion: https://postgr.es/m/15827-e6ba53a3a7ed543c@postgresql.org

src/backend/libpq/be-secure-common.c
src/interfaces/libpq/fe-connect.c

index a3edf27e86c6800780794183e961254e3317eaee..bee618abb931f17262a271c9a1393403132e4789 100644 (file)
@@ -112,9 +112,10 @@ run_ssl_passphrase_command(const char *prompt, bool is_server_start, char *buf,
        goto error;
    }
 
-   /* strip trailing newline */
+   /* strip trailing newline, including \r in case we're on Windows */
    len = strlen(buf);
-   if (len > 0 && buf[len - 1] == '\n')
+   while (len > 0 && (buf[len - 1] == '\n' ||
+                      buf[len - 1] == '\r'))
        buf[--len] = '\0';
 
 error:
index a8048ffad209dd810a19003fdf66749b120afec6..b93ed7662b616e34d573e5220944a2a61c2e93f3 100644 (file)
@@ -4661,6 +4661,8 @@ parseServiceFile(const char *serviceFile,
 
    while ((line = fgets(buf, sizeof(buf), f)) != NULL)
    {
+       int         len;
+
        linenr++;
 
        if (strlen(line) >= sizeof(buf) - 1)
@@ -4673,16 +4675,18 @@ parseServiceFile(const char *serviceFile,
            return 2;
        }
 
-       /* ignore EOL at end of line */
-       if (strlen(line) && line[strlen(line) - 1] == '\n')
-           line[strlen(line) - 1] = 0;
+       /* ignore EOL at end of line, including \r in case it's a DOS file */
+       len = strlen(line);
+       while (len > 0 && (line[len - 1] == '\n' ||
+                          line[len - 1] == '\r'))
+           line[--len] = '\0';
 
        /* ignore leading blanks */
        while (*line && isspace((unsigned char) line[0]))
            line++;
 
        /* ignore comments and empty lines */
-       if (strlen(line) == 0 || line[0] == '#')
+       if (line[0] == '\0' || line[0] == '#')
            continue;
 
        /* Check for right groupname */