Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 41f18f0

Browse files
committed
Promote pg_dumpall shell/connstr quoting functions to src/fe_utils.
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
1 parent bd65371 commit 41f18f0

File tree

4 files changed

+157
-154
lines changed

4 files changed

+157
-154
lines changed

src/bin/pg_dump/pg_dumpall.c

+7-151
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
5050
const char *name2);
5151
static void dumpDatabases(PGconn *conn);
5252
static void dumpTimestamp(const char *msg);
53-
static void doShellQuoting(PQExpBuffer buf, const char *str);
54-
static void doConnStrQuoting(PQExpBuffer buf, const char *str);
5553

5654
static int runPgDump(const char *dbname);
5755
static void buildShSecLabels(PGconn *conn, const char *catalog_name,
@@ -215,7 +213,7 @@ main(int argc, char *argv[])
215213
case 'f':
216214
filename = pg_strdup(optarg);
217215
appendPQExpBufferStr(pgdumpopts, " -f ");
218-
doShellQuoting(pgdumpopts, filename);
216+
appendShellString(pgdumpopts, filename);
219217
break;
220218

221219
case 'g':
@@ -252,7 +250,7 @@ main(int argc, char *argv[])
252250

253251
case 'S':
254252
appendPQExpBufferStr(pgdumpopts, " -S ");
255-
doShellQuoting(pgdumpopts, optarg);
253+
appendShellString(pgdumpopts, optarg);
256254
break;
257255

258256
case 't':
@@ -288,13 +286,13 @@ main(int argc, char *argv[])
288286

289287
case 2:
290288
appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout ");
291-
doShellQuoting(pgdumpopts, optarg);
289+
appendShellString(pgdumpopts, optarg);
292290
break;
293291

294292
case 3:
295293
use_role = pg_strdup(optarg);
296294
appendPQExpBufferStr(pgdumpopts, " --role ");
297-
doShellQuoting(pgdumpopts, use_role);
295+
appendShellString(pgdumpopts, use_role);
298296
break;
299297

300298
default:
@@ -1814,9 +1812,9 @@ runPgDump(const char *dbname)
18141812
* string.
18151813
*/
18161814
appendPQExpBuffer(connstrbuf, "%s dbname=", connstr);
1817-
doConnStrQuoting(connstrbuf, dbname);
1815+
appendConnStrVal(connstrbuf, dbname);
18181816

1819-
doShellQuoting(cmd, connstrbuf->data);
1817+
appendShellString(cmd, connstrbuf->data);
18201818

18211819
if (verbose)
18221820
fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
@@ -2096,7 +2094,7 @@ constructConnStr(const char **keywords, const char **values)
20962094
appendPQExpBufferChar(buf, ' ');
20972095
firstkeyword = false;
20982096
appendPQExpBuffer(buf, "%s=", keywords[i]);
2099-
doConnStrQuoting(buf, values[i]);
2097+
appendConnStrVal(buf, values[i]);
21002098
}
21012099

21022100
connstr = pg_strdup(buf->data);
@@ -2169,145 +2167,3 @@ dumpTimestamp(const char *msg)
21692167
if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
21702168
fprintf(OPF, "-- %s %s\n\n", msg, buf);
21712169
}
2172-
2173-
2174-
/*
2175-
* Append the given string to the buffer, with suitable quoting for passing
2176-
* the string as a value, in a keyword/pair value in a libpq connection
2177-
* string
2178-
*/
2179-
static void
2180-
doConnStrQuoting(PQExpBuffer buf, const char *str)
2181-
{
2182-
const char *s;
2183-
bool needquotes;
2184-
2185-
/*
2186-
* If the string consists entirely of plain ASCII characters, no need to
2187-
* quote it. This is quite conservative, but better safe than sorry.
2188-
*/
2189-
needquotes = false;
2190-
for (s = str; *s; s++)
2191-
{
2192-
if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
2193-
(*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
2194-
{
2195-
needquotes = true;
2196-
break;
2197-
}
2198-
}
2199-
2200-
if (needquotes)
2201-
{
2202-
appendPQExpBufferChar(buf, '\'');
2203-
while (*str)
2204-
{
2205-
/* ' and \ must be escaped by to \' and \\ */
2206-
if (*str == '\'' || *str == '\\')
2207-
appendPQExpBufferChar(buf, '\\');
2208-
2209-
appendPQExpBufferChar(buf, *str);
2210-
str++;
2211-
}
2212-
appendPQExpBufferChar(buf, '\'');
2213-
}
2214-
else
2215-
appendPQExpBufferStr(buf, str);
2216-
}
2217-
2218-
/*
2219-
* Append the given string to the shell command being built in the buffer,
2220-
* with suitable shell-style quoting to create exactly one argument.
2221-
*
2222-
* Forbid LF or CR characters, which have scant practical use beyond designing
2223-
* security breaches. The Windows command shell is unusable as a conduit for
2224-
* arguments containing LF or CR characters. A future major release should
2225-
* reject those characters in CREATE ROLE and CREATE DATABASE, because use
2226-
* there eventually leads to errors here.
2227-
*/
2228-
static void
2229-
doShellQuoting(PQExpBuffer buf, const char *str)
2230-
{
2231-
const char *p;
2232-
2233-
#ifndef WIN32
2234-
appendPQExpBufferChar(buf, '\'');
2235-
for (p = str; *p; p++)
2236-
{
2237-
if (*p == '\n' || *p == '\r')
2238-
{
2239-
fprintf(stderr,
2240-
_("shell command argument contains a newline or carriage return: \"%s\"\n"),
2241-
str);
2242-
exit(EXIT_FAILURE);
2243-
}
2244-
2245-
if (*p == '\'')
2246-
appendPQExpBufferStr(buf, "'\"'\"'");
2247-
else
2248-
appendPQExpBufferChar(buf, *p);
2249-
}
2250-
appendPQExpBufferChar(buf, '\'');
2251-
#else /* WIN32 */
2252-
int backslash_run_length = 0;
2253-
2254-
/*
2255-
* A Windows system() argument experiences two layers of interpretation.
2256-
* First, cmd.exe interprets the string. Its behavior is undocumented,
2257-
* but a caret escapes any byte except LF or CR that would otherwise have
2258-
* special meaning. Handling of a caret before LF or CR differs between
2259-
* "cmd.exe /c" and other modes, and it is unusable here.
2260-
*
2261-
* Second, the new process parses its command line to construct argv (see
2262-
* https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats
2263-
* backslash-double quote sequences specially.
2264-
*/
2265-
appendPQExpBufferStr(buf, "^\"");
2266-
for (p = str; *p; p++)
2267-
{
2268-
if (*p == '\n' || *p == '\r')
2269-
{
2270-
fprintf(stderr,
2271-
_("shell command argument contains a newline or carriage return: \"%s\"\n"),
2272-
str);
2273-
exit(EXIT_FAILURE);
2274-
}
2275-
2276-
/* Change N backslashes before a double quote to 2N+1 backslashes. */
2277-
if (*p == '"')
2278-
{
2279-
while (backslash_run_length)
2280-
{
2281-
appendPQExpBufferStr(buf, "^\\");
2282-
backslash_run_length--;
2283-
}
2284-
appendPQExpBufferStr(buf, "^\\");
2285-
}
2286-
else if (*p == '\\')
2287-
backslash_run_length++;
2288-
else
2289-
backslash_run_length = 0;
2290-
2291-
/*
2292-
* Decline to caret-escape the most mundane characters, to ease
2293-
* debugging and lest we approach the command length limit.
2294-
*/
2295-
if (!((*p >= 'a' && *p <= 'z') ||
2296-
(*p >= 'A' && *p <= 'Z') ||
2297-
(*p >= '0' && *p <= '9')))
2298-
appendPQExpBufferChar(buf, '^');
2299-
appendPQExpBufferChar(buf, *p);
2300-
}
2301-
2302-
/*
2303-
* Change N backslashes at end of argument to 2N backslashes, because they
2304-
* precede the double quote that terminates the argument.
2305-
*/
2306-
while (backslash_run_length)
2307-
{
2308-
appendPQExpBufferStr(buf, "^\\");
2309-
backslash_run_length--;
2310-
}
2311-
appendPQExpBufferStr(buf, "^\"");
2312-
#endif /* WIN32 */
2313-
}

src/fe_utils/string_utils.c

+143
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,149 @@ appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
378378
}
379379

380380

381+
/*
382+
* Append the given string to the shell command being built in the buffer,
383+
* with suitable shell-style quoting to create exactly one argument.
384+
*
385+
* Forbid LF or CR characters, which have scant practical use beyond designing
386+
* security breaches. The Windows command shell is unusable as a conduit for
387+
* arguments containing LF or CR characters. A future major release should
388+
* reject those characters in CREATE ROLE and CREATE DATABASE, because use
389+
* there eventually leads to errors here.
390+
*/
391+
void
392+
appendShellString(PQExpBuffer buf, const char *str)
393+
{
394+
const char *p;
395+
396+
#ifndef WIN32
397+
appendPQExpBufferChar(buf, '\'');
398+
for (p = str; *p; p++)
399+
{
400+
if (*p == '\n' || *p == '\r')
401+
{
402+
fprintf(stderr,
403+
_("shell command argument contains a newline or carriage return: \"%s\"\n"),
404+
str);
405+
exit(EXIT_FAILURE);
406+
}
407+
408+
if (*p == '\'')
409+
appendPQExpBufferStr(buf, "'\"'\"'");
410+
else
411+
appendPQExpBufferChar(buf, *p);
412+
}
413+
appendPQExpBufferChar(buf, '\'');
414+
#else /* WIN32 */
415+
int backslash_run_length = 0;
416+
417+
/*
418+
* A Windows system() argument experiences two layers of interpretation.
419+
* First, cmd.exe interprets the string. Its behavior is undocumented,
420+
* but a caret escapes any byte except LF or CR that would otherwise have
421+
* special meaning. Handling of a caret before LF or CR differs between
422+
* "cmd.exe /c" and other modes, and it is unusable here.
423+
*
424+
* Second, the new process parses its command line to construct argv (see
425+
* https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats
426+
* backslash-double quote sequences specially.
427+
*/
428+
appendPQExpBufferStr(buf, "^\"");
429+
for (p = str; *p; p++)
430+
{
431+
if (*p == '\n' || *p == '\r')
432+
{
433+
fprintf(stderr,
434+
_("shell command argument contains a newline or carriage return: \"%s\"\n"),
435+
str);
436+
exit(EXIT_FAILURE);
437+
}
438+
439+
/* Change N backslashes before a double quote to 2N+1 backslashes. */
440+
if (*p == '"')
441+
{
442+
while (backslash_run_length)
443+
{
444+
appendPQExpBufferStr(buf, "^\\");
445+
backslash_run_length--;
446+
}
447+
appendPQExpBufferStr(buf, "^\\");
448+
}
449+
else if (*p == '\\')
450+
backslash_run_length++;
451+
else
452+
backslash_run_length = 0;
453+
454+
/*
455+
* Decline to caret-escape the most mundane characters, to ease
456+
* debugging and lest we approach the command length limit.
457+
*/
458+
if (!((*p >= 'a' && *p <= 'z') ||
459+
(*p >= 'A' && *p <= 'Z') ||
460+
(*p >= '0' && *p <= '9')))
461+
appendPQExpBufferChar(buf, '^');
462+
appendPQExpBufferChar(buf, *p);
463+
}
464+
465+
/*
466+
* Change N backslashes at end of argument to 2N backslashes, because they
467+
* precede the double quote that terminates the argument.
468+
*/
469+
while (backslash_run_length)
470+
{
471+
appendPQExpBufferStr(buf, "^\\");
472+
backslash_run_length--;
473+
}
474+
appendPQExpBufferStr(buf, "^\"");
475+
#endif /* WIN32 */
476+
}
477+
478+
479+
/*
480+
* Append the given string to the buffer, with suitable quoting for passing
481+
* the string as a value, in a keyword/pair value in a libpq connection
482+
* string
483+
*/
484+
void
485+
appendConnStrVal(PQExpBuffer buf, const char *str)
486+
{
487+
const char *s;
488+
bool needquotes;
489+
490+
/*
491+
* If the string consists entirely of plain ASCII characters, no need to
492+
* quote it. This is quite conservative, but better safe than sorry.
493+
*/
494+
needquotes = false;
495+
for (s = str; *s; s++)
496+
{
497+
if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
498+
(*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
499+
{
500+
needquotes = true;
501+
break;
502+
}
503+
}
504+
505+
if (needquotes)
506+
{
507+
appendPQExpBufferChar(buf, '\'');
508+
while (*str)
509+
{
510+
/* ' and \ must be escaped by to \' and \\ */
511+
if (*str == '\'' || *str == '\\')
512+
appendPQExpBufferChar(buf, '\\');
513+
514+
appendPQExpBufferChar(buf, *str);
515+
str++;
516+
}
517+
appendPQExpBufferChar(buf, '\'');
518+
}
519+
else
520+
appendPQExpBufferStr(buf, str);
521+
}
522+
523+
381524
/*
382525
* Deconstruct the text representation of a 1-dimensional Postgres array
383526
* into individual items.

src/include/fe_utils/string_utils.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
*
33
* String-processing utility routines for frontend code
44
*
5-
* Assorted utility functions that are useful in constructing SQL queries
6-
* and interpreting backend output.
5+
* Utility functions that interpret backend output or quote strings for
6+
* assorted contexts.
77
*
88
*
99
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
@@ -40,6 +40,9 @@ extern void appendByteaLiteral(PQExpBuffer buf,
4040
const unsigned char *str, size_t length,
4141
bool std_strings);
4242

43+
extern void appendShellString(PQExpBuffer buf, const char *str);
44+
extern void appendConnStrVal(PQExpBuffer buf, const char *str);
45+
4346
extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
4447

4548
extern bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions,

src/port/system.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* Win32 needs double quotes at the beginning and end of system()
88
* strings. If not, it gets confused with multiple quoted strings.
99
* It also requires double-quotes around the executable name and
10-
* any files used for redirection. Other args can use single-quotes.
10+
* any files used for redirection. Filter other args through
11+
* appendShellString() to quote them.
1112
*
1213
* Generated using Win32 "CMD /?":
1314
*

0 commit comments

Comments
 (0)