setting, either globally or per-user.
+ For more information on schema handling, see
+ . In particular, the default
+ configuration is suitable only when the database has a single user or
+ a few mutually-trusting users.
+
+
The current effective value of the search path can be examined
appearing in search_path were resolved.
- For more information on schema handling, see .
-
choice. To do that, add SCHEMA
schema_name to the CREATE EXTENSION
command. By default, the objects will be placed in your current creation
- target schema, typically public .
+ target schema, which in turn defaults to public .
libpq -style connection info string, for example
hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres
- password=mypasswd.
+ password=mypasswd options=-csearch_path= .
For details see .
Alternatively, the name of a foreign server.
Notes
+ If untrusted users have access to a database that has not adopted a
+ secure schema usage pattern,
+ begin each session by removing publicly-writable schemas from
+ search_path . One could, for example,
+ add options=-csearch_path= to
+
connstr . This consideration is not specific
+ to dblink ; it applies to every interface for
+ executing arbitrary SQL commands.
+
+
Only superusers may use dblink_connect to create
non-password-authenticated connections. If non-superusers need this
Examples
-SELECT dblink_connect('dbname=postgres');
+SELECT dblink_connect('dbname=postgres options=-csearch_path= ');
dblink_connect
----------------
OK
(1 row)
-SELECT dblink_connect('myconn', 'dbname=postgres');
+SELECT dblink_connect('myconn', 'dbname=postgres options=-csearch_path= ');
dblink_connect
----------------
OK
SELECT *
- FROM dblink('dbname=mydb', 'select proname, prosrc from pg_proc')
+ FROM dblink('dbname=mydb options=-csearch_path=',
+ 'select proname, prosrc from pg_proc')
AS t1(proname name, prosrc text)
WHERE proname LIKE 'bytea%';
CREATE VIEW myremote_pg_proc AS
SELECT *
- FROM dblink('dbname=postgres', 'select proname, prosrc from pg_proc')
+ FROM dblink('dbname=postgres options=-csearch_path=',
+ 'select proname, prosrc from pg_proc')
AS t1(proname name, prosrc text);
SELECT * FROM myremote_pg_proc WHERE proname LIKE 'bytea%';
Examples
-SELECT * FROM dblink('dbname=postgres', 'select proname, prosrc from pg_proc')
+SELECT * FROM dblink('dbname=postgres options=-csearch_path=',
+ 'select proname, prosrc from pg_proc')
AS t1(proname name, prosrc text) WHERE proname LIKE 'bytea%';
proname | prosrc
------------+------------
byteaout | byteaout
(12 rows)
-SELECT dblink_connect('dbname=postgres');
+SELECT dblink_connect('dbname=postgres options=-csearch_path= ');
dblink_connect
----------------
OK
byteaout | byteaout
(12 rows)
-SELECT dblink_connect('myconn', 'dbname=regression');
+SELECT dblink_connect('myconn', 'dbname=regression options=-csearch_path= ');
dblink_connect
----------------
OK
Examples
-SELECT dblink_connect('dbname=postgres');
+SELECT dblink_connect('dbname=postgres options=-csearch_path= ');
dblink_connect
----------------
OK
Examples
-SELECT dblink_connect('dbname=postgres');
+SELECT dblink_connect('dbname=postgres options=-csearch_path= ');
dblink_connect
----------------
OK
Examples
-SELECT dblink_connect('dbname=postgres');
+SELECT dblink_connect('dbname=postgres options=-csearch_path= ');
dblink_connect
----------------
OK
in other schemas in the database.
+ The ability to create like-named objects in different schemas complicates
+ writing a query that references precisely the same objects every time. It
+ also opens up the potential for users to change the behavior of other
+ users' queries, maliciously or accidentally. Due to the prevalence of
+ unqualified names in queries and their use
+ in
PostgreSQL internals, adding a schema
+ to search_path effectively trusts all users having
+ CREATE privilege on that schema. When you run an
+ ordinary query, a malicious user able to create objects in a schema of
+ your search path can take control and execute arbitrary SQL functions as
+ though you executed them.
+
+
current
the schema
public . This allows all users that are able to
connect to a given database to create objects in its
- public schema. If you do
- not want to allow that, you can revoke that privilege:
+ public schema.
+ Some usage patterns call for
+ revoking that privilege:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
Usage Patterns
- Schemas can be used to organize your data in many ways. There are
- a few usage patterns that are recommended and are easily supported by
- the default configuration :
+ Schemas can be used to organize your data in many ways. There are a few
+ usage patterns easily supported by the default configuration, only one of
+ which suffices when database users mistrust other database users :
+
- If you do not create any schemas then all users access the
- public schema implicitly. This simulates the situation where
- schemas are not available at all. This setup is mainly
- recommended when there is only a single user or a few cooperating
- users in a database. This setup also allows smooth transition
- from the non-schema-aware world.
+ Constrain ordinary users to user-private schemas. To implement this,
+ issue REVOKE CREATE ON SCHEMA public FROM PUBLIC ,
+ and create a schema for each user with the same name as that user. If
+ affected users had logged in before this, consider auditing the public
+ schema for objects named like objects in
+ schema pg_catalog . Recall that the default search
+ path starts with $user , which resolves to the user
+ name. Therefore, if each user has a separate schema, they access their
+ own schemas by default.
- You can create a schema for each user with the same name as
- that user. Recall that the default search path starts with
- $user , which resolves to the user name.
- Therefore, if each user has a separate schema, they access their
- own schemas by default.
+ Remove the public schema from each user's default search path
+ using ALTER ROLE user SET
+ search_path = "$user". Everyone retains the ability to
+ create objects in the public schema, but only qualified names will
+ choose those objects. A user holding the CREATEROLE
+ privilege can undo this setting and issue arbitrary queries under the
+ identity of users relying on the setting. If you
+ grant CREATEROLE to users not warranting this
+ almost-superuser ability, use the first pattern instead.
+
+
- If you use this setup then you might also want to revoke access
- to the public schema (or drop it altogether), so users are
- truly constrained to their own schemas.
+ Remove the public schema from search_path in
+ postgresql.conf .
+ The ensuing user experience matches the previous pattern. In addition
+ to that pattern's implications for CREATEROLE , this
+ trusts database owners the same way. If you assign
+ the CREATEROLE
+ privilege, CREATEDB privilege or individual database
+ ownership to users not warranting almost-superuser access, use the
+ first pattern instead.
- To install shared applications (tables to be used by everyone,
- additional functions provided by third parties, etc.), put them
- into separate schemas. Remember to grant appropriate
- privileges to allow the other users to access them. Users can
- then refer to these additional objects by qualifying the names
- with a schema name, or they can put the additional schemas into
- their search path, as they choose.
+ Keep the default. All users access the public schema implicitly. This
+ simulates the situation where schemas are not available at all, giving
+ a smooth transition from the non-schema-aware world. However, any user
+ can issue arbitrary queries under the identity of any user not electing
+ to protect itself individually. This pattern is acceptable only when
+ the database has a single user or a few mutually-trusting users.
+
+ For any pattern, to install shared applications (tables to be used by
+ everyone, additional functions provided by third parties, etc.), put them
+ into separate schemas. Remember to grant appropriate privileges to allow
+ the other users to access them. Users can then refer to these additional
+ objects by qualifying the names with a schema name, or they can put the
+ additional schemas into their search path, as they choose.
+
Also, there is no concept of a public schema in the
SQL standard. For maximum conformance to the standard, you should
- not use (perhaps even remove) the public schema.
+ not use the public schema.
chapter).
+ If untrusted users have access to a database that has not adopted a
+ secure schema usage pattern,
+ begin each session by removing publicly-writable schemas
+ from search_path . For example,
+ add options=-csearch_path=
+ to options , or
+ issue EXEC SQL SELECT pg_catalog.set_config('search_path', '',
+ false); after connecting. This consideration is not specific to
+ ECPG; it applies to every interface for executing arbitrary SQL commands.
+
+
Here are some examples of CONNECT statements:
main()
{
EXEC SQL CONNECT TO testdb1 AS con1 USER testuser;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL CONNECT TO testdb2 AS con2 USER testuser;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL CONNECT TO testdb3 AS con3 USER testuser;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
/* This query would be executed in the last opened database "testdb3". */
EXEC SQL SELECT current_database() INTO :dbname;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO testdb;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
in = PGTYPESinterval_new();
EXEC SQL SELECT '1 min'::interval INTO :in;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO testdb;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
num = PGTYPESnumeric_new();
dec = PGTYPESdecimal_new();
memset(dbid, 0, sizeof(int) * 8);
EXEC SQL CONNECT TO testdb;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
/* Retrieve multiple rows into arrays at once. */
EXEC SQL SELECT oid,datname INTO :dbid, :dbname FROM pg_database;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO testdb AS con1 USER testuser;
+EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL PREPARE stmt1 FROM :stmt;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO testdb AS con1 USER testuser;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL PREPARE stmt1 FROM :query;
EXEC SQL DECLARE cur1 CURSOR FOR stmt1;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO uptimedb AS con1 USER uptime;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL PREPARE stmt1 FROM :query;
EXEC SQL DECLARE cur1 CURSOR FOR stmt1;
memset(buf, 1, buflen);
EXEC SQL CONNECT TO testdb AS con1;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
conn = ECPGget_PGconn("con1");
printf("conn = %p\n", conn);
TestCpp::TestCpp()
{
EXEC SQL CONNECT TO testdb1;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
}
void Test::test()
db_connect()
{
EXEC SQL CONNECT TO testdb1;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
}
void
ECPGdebug(1, stderr);
EXEC SQL CONNECT TO :dbname USER :user;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL SELECT version() INTO :ver;
EXEC SQL DISCONNECT;
printf("version: %s\n", ver);
EXEC SQL CONNECT TO :connection USER :user;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL SELECT version() INTO :ver;
EXEC SQL DISCONNECT;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO testdb AS con1 USER testuser;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL ALLOCATE DESCRIPTOR d;
/* Declare, open a cursor, and assign a descriptor to the cursor */
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO testdb AS con1;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL SELECT current_database(), 256 INTO :t:t_ind LIMIT 1;
main(void)
{
EXEC SQL CONNECT TO testdb AS con1;
+ EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
EXEC SQL ALLOCATE DESCRIPTOR d;
EXEC SQL DECLARE cur CURSOR FOR SELECT current_database(), 'hoge', 256;
EXEC SQL OPEN cur;
dropping the whole extension.
+
+
Defining Extension Objects
+
+
+ Widely-distributed extensions should assume little about the database
+ they occupy. In particular, unless you issued SET search_path =
+ pg_temp, assume each unqualified name could resolve to an
+ object that a malicious user has defined. Beware of constructs that
+ depend on search_path implicitly: IN
+ and CASE expression WHEN
+ always select an operator using the search path. In their place, use
+ OPERATOR(schema .=) ANY
+ and CASE WHEN expression .
+
+
+
+
Extension Files
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION pair" to load this file. \quit
-CREATE TYPE pair AS ( k text, v text );
-
-CREATE OR REPLACE FUNCTION pair(anyelement, text)
-RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair';
+CREATE TYPE pair AS ( k pg_catalog.text, v pg_catalog.text );
-CREATE OR REPLACE FUNCTION pair(text, anyelemen t)
-RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair ';
+CREATE OR REPLACE FUNCTION pair(pg_catalog.text, pg_catalog.tex t)
-CREATE OR REPLACE FUNCTION pair(anyelement, anyelement)
-RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair' ;
+CREATE OPERATOR ~> (LEFTARG = pg_catalog.text,
+ RIGHTARG = pg_catalog.text, PROCEDURE = pair) ;
-CREATE OR REPLACE FUNCTION pair(text, text)
-RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair;';
+-- "SET search_path" is easy to get right, but qualified names perform better.
+CREATE OR REPLACE FUNCTION lower(pair)
+RETURNS pair LANGUAGE SQL
+SET search_path = pg_temp;
-CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = anyelement, PROCEDURE = pair);
-CREATE OPERATOR ~> (LEFTARG = anyelement, RIGHTARG = text, PROCEDURE = pair);
-CREATE OPERATOR ~> (LEFTARG = anyelement, RIGHTARG = anyelement, PROCEDURE = pair);
-CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = text, PROCEDURE = pair) ;
+CREATE OR REPLACE FUNCTION pair_concat(pair, pair)
+RETURNS pair LANGUAGE SQL
+AS 'SELECT ROW($1.k OPERATOR(pg_catalog.||) $2.k,
]]>
# pair extension
comment = 'A key/value pair data type'
default_version = '1.0'
-relocatable = tru e
+relocatable = fals e
the return value for a successful connection before queries are sent
via the connection object.
+
+ If untrusted users have access to a database that has not adopted a
+ secure schema usage pattern,
+ begin each session by removing publicly-writable schemas from
+ search_path . One can set parameter key
+ word options to
+ value -csearch_path= . Alternately, one can
+ issue PQexec(conn , "SELECT
+ pg_catalog.set_config('search_path', '', false)") after
+ connecting. This consideration is not specific
+ to
libpq ; it applies to every interface for
+ executing arbitrary SQL commands.
+
+
+
On Unix, forking a process with open libpq connections can lead to
{
mydata *data;
PGresult *res;
- PGconn *conn = PQconnectdb("dbname = postgres");
+ PGconn *conn =
+ PQconnectdb("dbname=postgres options=-csearch_path=");
if (PQstatus(conn) != CONNECTION_OK)
{
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /*
+ * Should PQclear PGresult whenever it is no longer needed to avoid memory
+ * leaks
+ */
+ PQclear(res);
+
/*
* Our test case here involves using a cursor, for which we must be inside
* a transaction block. We could do the whole thing with a single
PQclear(res);
exit_nicely(conn);
}
-
- /*
- * Should PQclear PGresult whenever it is no longer needed to avoid memory
- * leaks
- */
PQclear(res);
/*
* populate a database with the following commands
* (provided in src/test/examples/testlibpq2.sql):
*
+ * CREATE SCHEMA TESTLIBPQ2;
+ * SET search_path = TESTLIBPQ2;
* CREATE TABLE TBL1 (i int4);
- *
* CREATE TABLE TBL2 (i int4);
- *
* CREATE RULE r1 AS ON INSERT TO TBL1 DO
* (INSERT INTO TBL2 VALUES (new.i); NOTIFY TBL2);
*
- * and do this four times:
+ * Start this program, then from psql do this four times:
*
- * INSERT INTO TBL1 VALUES (10);
+ * INSERT INTO TESTLIBPQ2.T BL1 VALUES (10);
*/
#ifdef WIN32
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /*
+ * Should PQclear PGresult whenever it is no longer needed to avoid memory
+ * leaks
+ */
+ PQclear(res);
+
/*
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
*/
PQclear(res);
exit_nicely(conn);
}
-
- /*
- * should PQclear PGresult whenever it is no longer needed to avoid memory
- * leaks
- */
PQclear(res);
/* Quit after four notifies are received. */
* Before running this, populate a database with the following commands
* (provided in src/test/examples/testlibpq3.sql):
*
+ * CREATE SCHEMA testlibpq3;
+ * SET search_path = testlibpq3;
* CREATE TABLE test1 (i int4, t text, b bytea);
- *
* INSERT INTO test1 values (1, 'joe''s place', '\\000\\001\\002\\003\\004');
* INSERT INTO test1 values (2, 'ho there', '\\004\\003\\002\\001\\000');
*
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn, "SET search_path = testlibpq3");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+ PQclear(res);
+
/*
* The point of this program is to illustrate use of PQexecParams() with
* out-of-line parameters, as well as binary transmission of data.
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+ PQclear(res);
+
res = PQexec(conn, "begin");
PQclear(res);
printf("importing file \"%s\" ...\n", in_filename);
database server.
+
+
Security
+
+ If untrusted users have access to a database that has not adopted a
+ secure schema usage pattern,
+ do not run
pgbench in that
+ database.
pgbench uses unqualified names and
+ does not manipulate the search path.
+
+
of the command are displayed on the screen.
+ If untrusted users have access to a database that has not adopted a
+ secure schema usage pattern,
+ begin your session by removing publicly-writable schemas
+ from search_path . One can
+ add options=-csearch_path= to the connection string or
+ issue SELECT pg_catalog.set_config('search_path', '',
+ false) before other SQL commands. This consideration is not
+ specific to
psql ; it applies to every interface
+ for executing arbitrary SQL commands.
+
+
Whenever a command is executed,
psql also polls
for asynchronous notification events generated by
-
Function and Trigger Security
+
Function Security
- Functions and triggers allow users to insert code into the backend
- server that other users might execute unintentionally. Hence, both
- mechanisms permit users to Trojan horse
- others with relative ease. The only real protection is tight
- control over who can define functions.
+ Functions, triggers and row-level security policies allow users to insert
+ code into the backend server that other users might execute
+ unintentionally. Hence, these mechanisms permit users to Trojan
+ horse others with relative ease. The strongest protection is tight
+ control over who can define objects. Where that is infeasible, write
+ queries referring only to objects having trusted owners. Remove
+ from search_path the public schema and any other schemas
+ that permit untrusted users to create objects.
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /*
+ * Should PQclear PGresult whenever it is no longer needed to avoid memory
+ * leaks
+ */
+ PQclear(res);
+
/*
* Our test case here involves using a cursor, for which we must be inside
* a transaction block. We could do the whole thing with a single
PQclear(res);
exit_nicely(conn);
}
-
- /*
- * Should PQclear PGresult whenever it is no longer needed to avoid memory
- * leaks
- */
PQclear(res);
/*
* populate a database with the following commands
* (provided in src/test/examples/testlibpq2.sql):
*
+ * CREATE SCHEMA TESTLIBPQ2;
+ * SET search_path = TESTLIBPQ2;
* CREATE TABLE TBL1 (i int4);
- *
* CREATE TABLE TBL2 (i int4);
- *
* CREATE RULE r1 AS ON INSERT TO TBL1 DO
* (INSERT INTO TBL2 VALUES (new.i); NOTIFY TBL2);
*
- * and do this four times:
+ * Start this program, then from psql do this four times:
*
- * INSERT INTO TBL1 VALUES (10);
+ * INSERT INTO TESTLIBPQ2.T BL1 VALUES (10);
*/
#ifdef WIN32
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /*
+ * Should PQclear PGresult whenever it is no longer needed to avoid memory
+ * leaks
+ */
+ PQclear(res);
+
/*
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
*/
PQclear(res);
exit_nicely(conn);
}
-
- /*
- * should PQclear PGresult whenever it is no longer needed to avoid memory
- * leaks
- */
PQclear(res);
/* Quit after four notifies are received. */
+CREATE SCHEMA TESTLIBPQ2;
+SET search_path = TESTLIBPQ2;
CREATE TABLE TBL1 (i int4);
-
CREATE TABLE TBL2 (i int4);
-
CREATE RULE r1 AS ON INSERT TO TBL1 DO
(INSERT INTO TBL2 VALUES (new.i); NOTIFY TBL2);
* Before running this, populate a database with the following commands
* (provided in src/test/examples/testlibpq3.sql):
*
+ * CREATE SCHEMA testlibpq3;
+ * SET search_path = testlibpq3;
* CREATE TABLE test1 (i int4, t text, b bytea);
- *
* INSERT INTO test1 values (1, 'joe''s place', '\\000\\001\\002\\003\\004');
* INSERT INTO test1 values (2, 'ho there', '\\004\\003\\002\\001\\000');
*
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn, "SET search_path = testlibpq3");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+ PQclear(res);
+
/*
* The point of this program is to illustrate use of PQexecParams() with
* out-of-line parameters, as well as binary transmission of data.
+CREATE SCHEMA testlibpq3;
+SET search_path = testlibpq3;
CREATE TABLE test1 (i int4, t text, b bytea);
-
INSERT INTO test1 values (1, 'joe''s place', '\\000\\001\\002\\003\\004');
INSERT INTO test1 values (2, 'ho there', '\\004\\003\\002\\001\\000');
}
static void
-check_conn(PGconn *conn, const char *dbName)
+check_prepare_ conn(PGconn *conn, const char *dbName)
{
+ PGresult *res;
+
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) != CONNECTION_OK)
{
dbName, PQerrorMessage(conn));
exit(1);
}
+
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit(1);
+ }
+ PQclear(res);
}
int
/* make a connection to the database */
conn1 = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName1);
- check_conn(conn1, dbName1);
+ check_prepare_ conn(conn1, dbName1);
conn2 = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName2);
- check_conn(conn2, dbName2);
+ check_prepare_ conn(conn2, dbName2);
/* start a transaction block */
res1 = PQexec(conn1, "BEGIN");
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+ PQclear(res);
+
res = PQexec(conn, "begin");
PQclear(res);
printf("importing file \"%s\" ...\n", in_filename);
exit_nicely(conn);
}
+ /* Set always-secure search path, so malicous users can't take control. */
+ res = PQexec(conn,
+ "SELECT pg_catalog.set_config('search_path', '', false)");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+ PQclear(res);
+
res = PQexec(conn, "begin");
PQclear(res);
printf("importing file \"%s\" ...\n", in_filename);