]> granicus.if.org Git - postgresql/commitdiff
Promote pg_dumpall shell/connstr quoting functions to src/fe_utils.
authorNoah Misch <noah@leadboat.com>
Mon, 8 Aug 2016 14:07:46 +0000 (10:07 -0400)
committerNoah Misch <noah@leadboat.com>
Mon, 8 Aug 2016 14:07:46 +0000 (10:07 -0400)
Rename these newly-extern functions with terms more typical of their new
neighbors.  No functional changes; a subsequent commit will use them in
more places.  Back-patch to 9.1 (all supported versions).  Back branches
lack src/fe_utils, so instead rename the functions in place; the
subsequent commit will copy them into the other programs using them.

Security: CVE-2016-5424

src/bin/pg_dump/pg_dumpall.c
src/fe_utils/string_utils.c
src/include/fe_utils/string_utils.h
src/port/system.c

index 70f8f91a6ad94715528aa9cb6d9ca1df5d899a52..0318f961b9e827e11f16dd8984316de64f5560fe 100644 (file)
@@ -50,8 +50,6 @@ static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
                                           const char *name2);
 static void dumpDatabases(PGconn *conn);
 static void dumpTimestamp(const char *msg);
-static void doShellQuoting(PQExpBuffer buf, const char *str);
-static void doConnStrQuoting(PQExpBuffer buf, const char *str);
 
 static int     runPgDump(const char *dbname);
 static void buildShSecLabels(PGconn *conn, const char *catalog_name,
@@ -215,7 +213,7 @@ main(int argc, char *argv[])
                        case 'f':
                                filename = pg_strdup(optarg);
                                appendPQExpBufferStr(pgdumpopts, " -f ");
-                               doShellQuoting(pgdumpopts, filename);
+                               appendShellString(pgdumpopts, filename);
                                break;
 
                        case 'g':
@@ -252,7 +250,7 @@ main(int argc, char *argv[])
 
                        case 'S':
                                appendPQExpBufferStr(pgdumpopts, " -S ");
-                               doShellQuoting(pgdumpopts, optarg);
+                               appendShellString(pgdumpopts, optarg);
                                break;
 
                        case 't':
@@ -288,13 +286,13 @@ main(int argc, char *argv[])
 
                        case 2:
                                appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout ");
-                               doShellQuoting(pgdumpopts, optarg);
+                               appendShellString(pgdumpopts, optarg);
                                break;
 
                        case 3:
                                use_role = pg_strdup(optarg);
                                appendPQExpBufferStr(pgdumpopts, " --role ");
-                               doShellQuoting(pgdumpopts, use_role);
+                               appendShellString(pgdumpopts, use_role);
                                break;
 
                        default:
@@ -1814,9 +1812,9 @@ runPgDump(const char *dbname)
         * string.
         */
        appendPQExpBuffer(connstrbuf, "%s dbname=", connstr);
-       doConnStrQuoting(connstrbuf, dbname);
+       appendConnStrVal(connstrbuf, dbname);
 
-       doShellQuoting(cmd, connstrbuf->data);
+       appendShellString(cmd, connstrbuf->data);
 
        if (verbose)
                fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
@@ -2096,7 +2094,7 @@ constructConnStr(const char **keywords, const char **values)
                        appendPQExpBufferChar(buf, ' ');
                firstkeyword = false;
                appendPQExpBuffer(buf, "%s=", keywords[i]);
-               doConnStrQuoting(buf, values[i]);
+               appendConnStrVal(buf, values[i]);
        }
 
        connstr = pg_strdup(buf->data);
@@ -2169,145 +2167,3 @@ dumpTimestamp(const char *msg)
        if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
                fprintf(OPF, "-- %s %s\n\n", msg, buf);
 }
-
-
-/*
- * Append the given string to the buffer, with suitable quoting for passing
- * the string as a value, in a keyword/pair value in a libpq connection
- * string
- */
-static void
-doConnStrQuoting(PQExpBuffer buf, const char *str)
-{
-       const char *s;
-       bool            needquotes;
-
-       /*
-        * If the string consists entirely of plain ASCII characters, no need to
-        * quote it. This is quite conservative, but better safe than sorry.
-        */
-       needquotes = false;
-       for (s = str; *s; s++)
-       {
-               if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
-                         (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
-               {
-                       needquotes = true;
-                       break;
-               }
-       }
-
-       if (needquotes)
-       {
-               appendPQExpBufferChar(buf, '\'');
-               while (*str)
-               {
-                       /* ' and \ must be escaped by to \' and \\ */
-                       if (*str == '\'' || *str == '\\')
-                               appendPQExpBufferChar(buf, '\\');
-
-                       appendPQExpBufferChar(buf, *str);
-                       str++;
-               }
-               appendPQExpBufferChar(buf, '\'');
-       }
-       else
-               appendPQExpBufferStr(buf, str);
-}
-
-/*
- * Append the given string to the shell command being built in the buffer,
- * with suitable shell-style quoting to create exactly one argument.
- *
- * Forbid LF or CR characters, which have scant practical use beyond designing
- * security breaches.  The Windows command shell is unusable as a conduit for
- * arguments containing LF or CR characters.  A future major release should
- * reject those characters in CREATE ROLE and CREATE DATABASE, because use
- * there eventually leads to errors here.
- */
-static void
-doShellQuoting(PQExpBuffer buf, const char *str)
-{
-       const char *p;
-
-#ifndef WIN32
-       appendPQExpBufferChar(buf, '\'');
-       for (p = str; *p; p++)
-       {
-               if (*p == '\n' || *p == '\r')
-               {
-                       fprintf(stderr,
-                                       _("shell command argument contains a newline or carriage return: \"%s\"\n"),
-                                       str);
-                       exit(EXIT_FAILURE);
-               }
-
-               if (*p == '\'')
-                       appendPQExpBufferStr(buf, "'\"'\"'");
-               else
-                       appendPQExpBufferChar(buf, *p);
-       }
-       appendPQExpBufferChar(buf, '\'');
-#else                                                  /* WIN32 */
-       int                     backslash_run_length = 0;
-
-       /*
-        * A Windows system() argument experiences two layers of interpretation.
-        * First, cmd.exe interprets the string.  Its behavior is undocumented,
-        * but a caret escapes any byte except LF or CR that would otherwise have
-        * special meaning.  Handling of a caret before LF or CR differs between
-        * "cmd.exe /c" and other modes, and it is unusable here.
-        *
-        * Second, the new process parses its command line to construct argv (see
-        * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx).  This treats
-        * backslash-double quote sequences specially.
-        */
-       appendPQExpBufferStr(buf, "^\"");
-       for (p = str; *p; p++)
-       {
-               if (*p == '\n' || *p == '\r')
-               {
-                       fprintf(stderr,
-                                       _("shell command argument contains a newline or carriage return: \"%s\"\n"),
-                                       str);
-                       exit(EXIT_FAILURE);
-               }
-
-               /* Change N backslashes before a double quote to 2N+1 backslashes. */
-               if (*p == '"')
-               {
-                       while (backslash_run_length)
-                       {
-                               appendPQExpBufferStr(buf, "^\\");
-                               backslash_run_length--;
-                       }
-                       appendPQExpBufferStr(buf, "^\\");
-               }
-               else if (*p == '\\')
-                       backslash_run_length++;
-               else
-                       backslash_run_length = 0;
-
-               /*
-                * Decline to caret-escape the most mundane characters, to ease
-                * debugging and lest we approach the command length limit.
-                */
-               if (!((*p >= 'a' && *p <= 'z') ||
-                         (*p >= 'A' && *p <= 'Z') ||
-                         (*p >= '0' && *p <= '9')))
-                       appendPQExpBufferChar(buf, '^');
-               appendPQExpBufferChar(buf, *p);
-       }
-
-       /*
-        * Change N backslashes at end of argument to 2N backslashes, because they
-        * precede the double quote that terminates the argument.
-        */
-       while (backslash_run_length)
-       {
-               appendPQExpBufferStr(buf, "^\\");
-               backslash_run_length--;
-       }
-       appendPQExpBufferStr(buf, "^\"");
-#endif   /* WIN32 */
-}
index 04943a99aa14d72a81a1af87e76509d5370d3d9f..4cf08dbdcaa187cb330035585a9bb12e972d34d4 100644 (file)
@@ -378,6 +378,149 @@ appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
 }
 
 
+/*
+ * Append the given string to the shell command being built in the buffer,
+ * with suitable shell-style quoting to create exactly one argument.
+ *
+ * Forbid LF or CR characters, which have scant practical use beyond designing
+ * security breaches.  The Windows command shell is unusable as a conduit for
+ * arguments containing LF or CR characters.  A future major release should
+ * reject those characters in CREATE ROLE and CREATE DATABASE, because use
+ * there eventually leads to errors here.
+ */
+void
+appendShellString(PQExpBuffer buf, const char *str)
+{
+       const char *p;
+
+#ifndef WIN32
+       appendPQExpBufferChar(buf, '\'');
+       for (p = str; *p; p++)
+       {
+               if (*p == '\n' || *p == '\r')
+               {
+                       fprintf(stderr,
+                                       _("shell command argument contains a newline or carriage return: \"%s\"\n"),
+                                       str);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (*p == '\'')
+                       appendPQExpBufferStr(buf, "'\"'\"'");
+               else
+                       appendPQExpBufferChar(buf, *p);
+       }
+       appendPQExpBufferChar(buf, '\'');
+#else                                                  /* WIN32 */
+       int                     backslash_run_length = 0;
+
+       /*
+        * A Windows system() argument experiences two layers of interpretation.
+        * First, cmd.exe interprets the string.  Its behavior is undocumented,
+        * but a caret escapes any byte except LF or CR that would otherwise have
+        * special meaning.  Handling of a caret before LF or CR differs between
+        * "cmd.exe /c" and other modes, and it is unusable here.
+        *
+        * Second, the new process parses its command line to construct argv (see
+        * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx).  This treats
+        * backslash-double quote sequences specially.
+        */
+       appendPQExpBufferStr(buf, "^\"");
+       for (p = str; *p; p++)
+       {
+               if (*p == '\n' || *p == '\r')
+               {
+                       fprintf(stderr,
+                                       _("shell command argument contains a newline or carriage return: \"%s\"\n"),
+                                       str);
+                       exit(EXIT_FAILURE);
+               }
+
+               /* Change N backslashes before a double quote to 2N+1 backslashes. */
+               if (*p == '"')
+               {
+                       while (backslash_run_length)
+                       {
+                               appendPQExpBufferStr(buf, "^\\");
+                               backslash_run_length--;
+                       }
+                       appendPQExpBufferStr(buf, "^\\");
+               }
+               else if (*p == '\\')
+                       backslash_run_length++;
+               else
+                       backslash_run_length = 0;
+
+               /*
+                * Decline to caret-escape the most mundane characters, to ease
+                * debugging and lest we approach the command length limit.
+                */
+               if (!((*p >= 'a' && *p <= 'z') ||
+                         (*p >= 'A' && *p <= 'Z') ||
+                         (*p >= '0' && *p <= '9')))
+                       appendPQExpBufferChar(buf, '^');
+               appendPQExpBufferChar(buf, *p);
+       }
+
+       /*
+        * Change N backslashes at end of argument to 2N backslashes, because they
+        * precede the double quote that terminates the argument.
+        */
+       while (backslash_run_length)
+       {
+               appendPQExpBufferStr(buf, "^\\");
+               backslash_run_length--;
+       }
+       appendPQExpBufferStr(buf, "^\"");
+#endif   /* WIN32 */
+}
+
+
+/*
+ * Append the given string to the buffer, with suitable quoting for passing
+ * the string as a value, in a keyword/pair value in a libpq connection
+ * string
+ */
+void
+appendConnStrVal(PQExpBuffer buf, const char *str)
+{
+       const char *s;
+       bool            needquotes;
+
+       /*
+        * If the string consists entirely of plain ASCII characters, no need to
+        * quote it. This is quite conservative, but better safe than sorry.
+        */
+       needquotes = false;
+       for (s = str; *s; s++)
+       {
+               if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
+                         (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
+               {
+                       needquotes = true;
+                       break;
+               }
+       }
+
+       if (needquotes)
+       {
+               appendPQExpBufferChar(buf, '\'');
+               while (*str)
+               {
+                       /* ' and \ must be escaped by to \' and \\ */
+                       if (*str == '\'' || *str == '\\')
+                               appendPQExpBufferChar(buf, '\\');
+
+                       appendPQExpBufferChar(buf, *str);
+                       str++;
+               }
+               appendPQExpBufferChar(buf, '\'');
+       }
+       else
+               appendPQExpBufferStr(buf, str);
+}
+
+
 /*
  * Deconstruct the text representation of a 1-dimensional Postgres array
  * into individual items.
index 733e337910b3853cf7abb830fe238cbd75059ed2..c709406628e1b1780e3f2f77bd5996a165bd2ee3 100644 (file)
@@ -2,8 +2,8 @@
  *
  * String-processing utility routines for frontend code
  *
- * Assorted utility functions that are useful in constructing SQL queries
- * and interpreting backend output.
+ * Utility functions that interpret backend output or quote strings for
+ * assorted contexts.
  *
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
@@ -40,6 +40,9 @@ extern void appendByteaLiteral(PQExpBuffer buf,
                                   const unsigned char *str, size_t length,
                                   bool std_strings);
 
+extern void appendShellString(PQExpBuffer buf, const char *str);
+extern void appendConnStrVal(PQExpBuffer buf, const char *str);
+
 extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
 
 extern bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions,
index f685a4e0b2d863700df4a24324837ac4f2b0009a..b0f98efae62f777d9f4810935a7faff1dcf6fc95 100644 (file)
@@ -7,7 +7,8 @@
  *     Win32 needs double quotes at the beginning and end of system()
  *     strings.  If not, it gets confused with multiple quoted strings.
  *     It also requires double-quotes around the executable name and
- *     any files used for redirection.  Other args can use single-quotes.
+ *     any files used for redirection.  Filter other args through
+ *     appendShellString() to quote them.
  *
  *     Generated using Win32 "CMD /?":
  *