diff --git a/Makefile b/Makefile index f90c10ce..fdd1da0f 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ HEADERS = $(wildcard *.h) repmgrd_OBJS = dbutils.o config.o repmgrd.o log.o strutil.o -repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o log.o strutil.o dirmod.o +repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o log.o strutil.o dirmod.o escape.o DATA = repmgr.sql uninstall_repmgr.sql diff --git a/escape.c b/escape.c new file mode 100644 index 00000000..6295a552 --- /dev/null +++ b/escape.c @@ -0,0 +1,79 @@ +/* + * + * escape.c + * parameter escaping functions + * + * Copyright (C) 2ndQuadrant, 2010-2016 + * + * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#if (PG_VERSION_NUM < 90600) + +#include "repmgr.h" +#include "escape.h" + +/* + * 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 + * + * This function is copied from src/bin/pg_dump/dumputils.c + * as it is only publicly exposed from 9.6 + */ +void +appendConnStrVal(PQExpBuffer buf, const char *str) +{ + const char *s; + bool needquotes; + + /* + * If the string is one or more plain ASCII characters, no need to quote + * it. This is quite conservative, but better safe than sorry. + */ + needquotes = true; + for (s = str; *s; s++) + { + if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || *s == '_' || *s == '.')) + { + needquotes = true; + break; + } + needquotes = false; + } + + 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); +} + +#endif diff --git a/escape.h b/escape.h new file mode 100644 index 00000000..f3dd3e85 --- /dev/null +++ b/escape.h @@ -0,0 +1,26 @@ +/* + * escape.h + * Copyright (c) 2ndQuadrant, 2010-2016 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef _ESCAPE_H_ +#define _ESCAPE_H_ + +extern void +appendConnStrVal(PQExpBuffer buf, const char *str); + +#endif diff --git a/repmgr.c b/repmgr.c index 0f3632aa..acc66034 100644 --- a/repmgr.c +++ b/repmgr.c @@ -57,13 +57,19 @@ #include "storage/fd.h" /* for PG_TEMP_FILE_PREFIX */ - #include "log.h" #include "config.h" #include "check_dir.h" #include "strutil.h" #include "version.h" +#if (PG_VERSION_NUM < 90600) +#include "escape.h" +#else +#include "fe_utils/string_utils.h" +#include "postgres_fe.h" +#endif + #ifndef RECOVERY_COMMAND_FILE #define RECOVERY_COMMAND_FILE "recovery.conf" #endif @@ -6611,6 +6617,9 @@ do_help(void) /* * Creates a recovery.conf file for a standby + * + * A database connection pointer is required for escaping primary_conninfo + * parameters. When cloning from Barman and --no-upstream-conne ) this might not be */ static bool create_recovery_file(const char *data_dir, t_conninfo_param_list *recovery_conninfo) @@ -6650,8 +6659,10 @@ create_recovery_file(const char *data_dir, t_conninfo_param_list *recovery_conni */ if (strlen(runtime_options.upstream_conninfo)) { + char *escaped = escape_recovery_conf_value(runtime_options.upstream_conninfo); maxlen_snprintf(line, "primary_conninfo = '%s'\n", - runtime_options.upstream_conninfo); + escaped); + free(escaped); } /* * otherwise use the conninfo inferred from the upstream connection @@ -6732,6 +6743,7 @@ write_primary_conninfo(char *line, t_conninfo_param_list *param_list) PQExpBufferData conninfo_buf; bool application_name_provided = false; int c; + char *escaped; initPQExpBuffer(&conninfo_buf); @@ -6755,20 +6767,28 @@ write_primary_conninfo(char *line, t_conninfo_param_list *param_list) if (strcmp(param_list->keywords[c], "application_name") == 0) application_name_provided = true; - /* XXX escape option->values */ - appendPQExpBuffer(&conninfo_buf, "%s=%s", param_list->keywords[c], param_list->values[c]); + appendPQExpBuffer(&conninfo_buf, "%s=", param_list->keywords[c]); + appendConnStrVal(&conninfo_buf, param_list->values[c]); } /* `application_name` not provided - default to repmgr node name */ if (application_name_provided == false) { if (strlen(options.node_name)) - appendPQExpBuffer(&conninfo_buf, " application_name=%s", options.node_name); + { + appendPQExpBuffer(&conninfo_buf, " application_name="); + appendConnStrVal(&conninfo_buf, options.node_name); + } else + { appendPQExpBuffer(&conninfo_buf, " application_name=repmgr"); + } } + escaped = escape_recovery_conf_value(conninfo_buf.data); - maxlen_snprintf(line, "primary_conninfo = '%s'\n", conninfo_buf.data); + maxlen_snprintf(line, "primary_conninfo = '%s'\n", escaped); + + free(escaped); termPQExpBuffer(&conninfo_buf); } diff --git a/strutil.c b/strutil.c index 4f116602..db6c024e 100644 --- a/strutil.c +++ b/strutil.c @@ -118,3 +118,21 @@ appendShellString(PQExpBuffer buf, const char *str) appendPQExpBufferChar(buf, '\''); } + + +/* + * Escape a string for use as a parameter in recovery.conf + * Caller must free returned value + */ +char * +escape_recovery_conf_value(const char *src) +{ + char *result = escape_single_quotes_ascii(src); + + if (!result) + { + fprintf(stderr, _("%s: out of memory\n"), progname()); + exit(ERR_INTERNAL); + } + return result; +} diff --git a/strutil.h b/strutil.h index 076fdd20..da436b3b 100644 --- a/strutil.h +++ b/strutil.h @@ -51,4 +51,7 @@ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); extern void appendShellString(PQExpBuffer buf, const char *str); + +extern char * +escape_recovery_conf_value(const char *src); #endif /* _STRUTIL_H_ */