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 -