diff -cprN head/doc/src/sgml/catalogs.sgml work/doc/src/sgml/catalogs.sgml
*** head/doc/src/sgml/catalogs.sgml Fri Dec 11 12:39:49 2009
--- work/doc/src/sgml/catalogs.sgml Fri Dec 11 16:38:25 2009
***************
*** 3136,3142 ****
pg_largeobject should not be readable by the
! public, since the catalog contains data in large objects of all users.
pg_largeobject_metadata> is a publicly readable catalog
that only contains identifiers of large objects.
--- 3136,3143 ----
pg_largeobject should not be readable by the
! public (except for loid), since the catalog
! contains data in large objects of all users.
pg_largeobject_metadata> is a publicly readable catalog
that only contains identifiers of large objects.
Binary files head/dump.dmp and work/dump.dmp differ
diff -cprN head/src/bin/initdb/initdb.c work/src/bin/initdb/initdb.c
*** head/src/bin/initdb/initdb.c Fri Dec 11 12:39:49 2009
--- work/src/bin/initdb/initdb.c Fri Dec 11 16:38:25 2009
*************** setup_privileges(void)
*** 1784,1789 ****
--- 1784,1790 ----
"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n",
"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n",
"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n",
+ "GRANT SELECT (loid) ON pg_largeobject TO PUBLIC;\n",
NULL
};
diff -cprN head/src/bin/pg_dump/pg_backup_archiver.c work/src/bin/pg_dump/pg_backup_archiver.c
*** head/src/bin/pg_dump/pg_backup_archiver.c Tue Oct 6 16:37:35 2009
--- work/src/bin/pg_dump/pg_backup_archiver.c Fri Dec 11 17:03:56 2009
*************** StartRestoreBlob(ArchiveHandle *AH, Oid
*** 914,921 ****
ahlog(AH, 2, "restoring large object with OID %u\n", oid);
if (drop)
! ahprintf(AH, "SELECT CASE WHEN EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u') THEN pg_catalog.lo_unlink('%u') END;\n",
! oid, oid);
if (AH->connection)
{
--- 914,920 ----
ahlog(AH, 2, "restoring large object with OID %u\n", oid);
if (drop)
! DropBlobIfExists(AH, oid);
if (AH->connection)
{
diff -cprN head/src/bin/pg_dump/pg_backup_archiver.h work/src/bin/pg_dump/pg_backup_archiver.h
*** head/src/bin/pg_dump/pg_backup_archiver.h Mon Aug 10 09:40:51 2009
--- work/src/bin/pg_dump/pg_backup_archiver.h Fri Dec 11 16:56:26 2009
*************** extern void InitArchiveFmt_Tar(ArchiveHa
*** 371,376 ****
--- 371,377 ----
extern bool isValidTarHeader(char *header);
extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
+ extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid);
int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
int ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3)));
diff -cprN head/src/bin/pg_dump/pg_backup_db.c work/src/bin/pg_dump/pg_backup_db.c
*** head/src/bin/pg_dump/pg_backup_db.c Fri Jun 12 09:52:43 2009
--- work/src/bin/pg_dump/pg_backup_db.c Fri Dec 11 16:57:35 2009
*************** CommitTransaction(ArchiveHandle *AH)
*** 652,657 ****
--- 652,679 ----
ExecuteSqlCommand(AH, "COMMIT", "could not commit database transaction");
}
+ void
+ DropBlobIfExists(ArchiveHandle *AH, Oid oid)
+ {
+ const char *lo_relname;
+ const char *lo_colname;
+
+ if (PQserverVersion(AH->connection) >= 80500)
+ {
+ lo_relname = "pg_largeobject_metadata";
+ lo_colname = "oid";
+ }
+ else
+ {
+ lo_relname = "pg_largeobject";
+ lo_colname = "loid";
+ }
+
+ /* Call lo_unlink only if exists to avoid not-found error. */
+ ahprintf(AH, "SELECT CASE WHEN EXISTS(SELECT 1 FROM pg_catalog.%s WHERE %s = '%u') THEN pg_catalog.lo_unlink('%u') END;\n",
+ lo_relname, lo_colname, oid, oid);
+ }
+
static bool
_isIdentChar(unsigned char c)
{
diff -cprN head/src/bin/pg_dump/pg_backup_null.c work/src/bin/pg_dump/pg_backup_null.c
*** head/src/bin/pg_dump/pg_backup_null.c Wed Aug 5 10:11:11 2009
--- work/src/bin/pg_dump/pg_backup_null.c Fri Dec 11 16:58:30 2009
*************** _StartBlob(ArchiveHandle *AH, TocEntry *
*** 151,158 ****
die_horribly(AH, NULL, "invalid OID for large object\n");
if (AH->ropt->dropSchema)
! ahprintf(AH, "SELECT CASE WHEN EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u') THEN pg_catalog.lo_unlink('%u') END;\n",
! oid, oid);
ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
oid, INV_WRITE);
--- 151,157 ----
die_horribly(AH, NULL, "invalid OID for large object\n");
if (AH->ropt->dropSchema)
! DropBlobIfExists(AH, oid);
ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
oid, INV_WRITE);
diff -cprN head/src/bin/pg_dump/pg_dump.c work/src/bin/pg_dump/pg_dump.c
*** head/src/bin/pg_dump/pg_dump.c Fri Dec 11 12:39:49 2009
--- work/src/bin/pg_dump/pg_dump.c Fri Dec 11 16:38:26 2009
*************** hasBlobs(Archive *AH)
*** 1945,1951 ****
selectSourceSchema("pg_catalog");
/* Check for BLOB OIDs */
! if (AH->remoteVersion >= 70100)
blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
else
blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
--- 1945,1953 ----
selectSourceSchema("pg_catalog");
/* Check for BLOB OIDs */
! if (AH->remoteVersion >= 80500)
! blobQry = "SELECT oid FROM pg_largeobject_metadata LIMIT 1";
! else if (AH->remoteVersion >= 70100)
blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
else
blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
*************** dumpBlobs(Archive *AH, void *arg)
*** 1981,1987 ****
selectSourceSchema("pg_catalog");
/* Cursor to get all BLOB OIDs */
! if (AH->remoteVersion >= 70100)
blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
else
blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
--- 1983,1991 ----
selectSourceSchema("pg_catalog");
/* Cursor to get all BLOB OIDs */
! if (AH->remoteVersion >= 80500)
! blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
! else if (AH->remoteVersion >= 70100)
blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
else
blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
diff -cprN head/src/test/regress/expected/privileges.out work/src/test/regress/expected/privileges.out
*** head/src/test/regress/expected/privileges.out Fri Dec 11 12:39:49 2009
--- work/src/test/regress/expected/privileges.out Fri Dec 11 16:38:25 2009
*************** SELECT lo_unlink(1002);
*** 1041,1046 ****
--- 1041,1061 ----
SELECT lo_export(1001, '/dev/null'); -- to be denied
ERROR: must be superuser to use server-side lo_export()
HINT: Anyone can use the client-side lo_export() provided by libpq.
+ -- don't allow unpriv users to access pg_largeobject contents
+ \c -
+ SELECT * FROM pg_largeobject LIMIT 0;
+ loid | pageno | data
+ ------+--------+------
+ (0 rows)
+
+ SET SESSION AUTHORIZATION regressuser1;
+ SELECT * FROM pg_largeobject LIMIT 0; -- to be denied
+ ERROR: permission denied for relation pg_largeobject
+ SELECT loid FROM pg_largeobject LIMIT 0;
+ loid
+ ------
+ (0 rows)
+
-- test default ACLs
\c -
CREATE SCHEMA testns;
diff -cprN head/src/test/regress/sql/privileges.sql work/src/test/regress/sql/privileges.sql
*** head/src/test/regress/sql/privileges.sql Fri Dec 11 12:39:49 2009
--- work/src/test/regress/sql/privileges.sql Fri Dec 11 16:38:25 2009
*************** SELECT lo_truncate(lo_open(1002, x'20000
*** 565,570 ****
--- 565,578 ----
SELECT lo_unlink(1002);
SELECT lo_export(1001, '/dev/null'); -- to be denied
+ -- don't allow unpriv users to access pg_largeobject contents
+ \c -
+ SELECT * FROM pg_largeobject LIMIT 0;
+
+ SET SESSION AUTHORIZATION regressuser1;
+ SELECT * FROM pg_largeobject LIMIT 0; -- to be denied
+ SELECT loid FROM pg_largeobject LIMIT 0;
+
-- test default ACLs
\c -