From 6a7273e14c4df53f5aba191132699ce217901958 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 2 Nov 2002 02:33:03 +0000 Subject: [PATCH] Fix permissions-checking bugs and namespace-search-path bugs in CONVERSION code. Still need to figure out what to do about inappropriate coding in parsing. --- doc/src/sgml/ref/create_conversion.sgml | 31 +++---- src/backend/catalog/namespace.c | 35 ++++---- src/backend/catalog/pg_conversion.c | 115 ++++++++---------------- src/backend/commands/conversioncmds.c | 40 +++------ src/include/catalog/pg_conversion.h | 9 +- src/include/utils/syscache.h | 4 +- 6 files changed, 86 insertions(+), 148 deletions(-) diff --git a/doc/src/sgml/ref/create_conversion.sgml b/doc/src/sgml/ref/create_conversion.sgml index 20abdf3bd4..bf8ec00ff7 100644 --- a/doc/src/sgml/ref/create_conversion.sgml +++ b/doc/src/sgml/ref/create_conversion.sgml @@ -1,4 +1,4 @@ - + @@ -14,8 +14,7 @@ CREATE [DEFAULT] CONVERSION conversion_name - FOR source_encoding - TO dest_encoding FROM funcname + FOR source_encoding TO dest_encoding FROM funcname @@ -24,18 +23,16 @@ CREATE [DEFAULT] CONVERSION conversion_name CREATE CONVERSION defines a new encoding - conversion. There are two kinds of conversions. A default - conversion is used for an automatic encoding conversion between - frontend and backend. There should be only one default conversion - for source/destination encodings pair in a schema. None default - conversion never be used for the automatic conversion. Instead it - can be used for CONVERT() function. + conversion. Conversion names may be used in the CONVERT() function + to specify a particular encoding conversion. Also, conversions that + are marked DEFAULT can be used for automatic encoding conversion between + frontend and backend. For this purpose, two conversions, from encoding A to + B AND from encoding B to A, must be defined. To be able to create a conversion, you must have the execute right - on the function and the usage right on the schema the function - belongs to. + on the function and the create right on the destination schema. @@ -49,11 +46,7 @@ CREATE [DEFAULT] CONVERSION conversion_name The DEFAULT clause indicates that this conversion is the default for this particular source to destination encoding. There should be only one default encoding in a schema - for the encoding pair. A default encoding can be used for not - only CONVERT() function, but also for the automatic encoding - conversion between frontend and backend. For this purpose, two - conversions, from encoding A to B AND encoding B to A, must be - defined. + for the encoding pair. @@ -64,8 +57,8 @@ CREATE [DEFAULT] CONVERSION conversion_name The name of the conversion. The conversion name may be - schema-qualified. If it is not, a conversion is defined in the - current schema. The conversion name must be unique with in a + schema-qualified. If it is not, the conversion is defined in the + current schema. The conversion name must be unique within a schema. @@ -102,7 +95,7 @@ CREATE [DEFAULT] CONVERSION conversion_name - The function must have following signature: + The function must have the following signature: conv_proc( diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index c5a5c70ebc..bd2eaf52cd 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -13,7 +13,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.36 2002/09/23 20:43:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.37 2002/11/02 02:33:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1275,32 +1275,33 @@ PopSpecialNamespace(Oid namespaceId) Oid FindConversionByName(List *name) { + char *schemaname; char *conversion_name; Oid namespaceId; Oid conoid; List *lptr; - /* Convert list of names to a name and namespace */ - namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name); + /* deconstruct the name list */ + DeconstructQualifiedName(name, &schemaname, &conversion_name); - if (length(name) > 1) + if (schemaname) { - /* Check we have usage rights in target namespace */ - if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK) - return InvalidOid; - + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(schemaname); return FindConversion(conversion_name, namespaceId); } - - recomputeNamespacePath(); - - foreach(lptr, namespaceSearchPath) + else { - Oid namespaceId = (Oid) lfirsti(lptr); + /* search for it in search path */ + recomputeNamespacePath(); - conoid = FindConversion(conversion_name, namespaceId); - if (OidIsValid(conoid)) - return conoid; + foreach(lptr, namespaceSearchPath) + { + namespaceId = (Oid) lfirsti(lptr); + conoid = FindConversion(conversion_name, namespaceId); + if (OidIsValid(conoid)) + return conoid; + } } /* Not found in path */ @@ -1308,7 +1309,7 @@ FindConversionByName(List *name) } /* - * FindDefaultConversionProc - find default encoding cnnversion proc + * FindDefaultConversionProc - find default encoding conversion proc */ Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding) diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index bd721507ed..c724d7e15a 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.6 2002/09/04 20:31:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.7 2002/11/02 02:33:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,16 +30,15 @@ #include "utils/acl.h" #include "miscadmin.h" -/* ---------------- +/* * ConversionCreate * - * Add a new tuple to pg_coversion. - * --------------- + * Add a new tuple to pg_conversion. */ Oid ConversionCreate(const char *conname, Oid connamespace, int32 conowner, - int4 conforencoding, int4 contoencoding, + int32 conforencoding, int32 contoencoding, Oid conproc, bool def) { int i; @@ -58,7 +57,7 @@ ConversionCreate(const char *conname, Oid connamespace, elog(ERROR, "no conversion name supplied"); /* make sure there is no existing conversion of same name */ - if (SearchSysCacheExists(CONNAMESP, + if (SearchSysCacheExists(CONNAMENSP, PointerGetDatum(conname), ObjectIdGetDatum(connamespace), 0, 0)) @@ -74,7 +73,8 @@ ConversionCreate(const char *conname, Oid connamespace, conforencoding, contoencoding)) elog(ERROR, "default conversion for %s to %s already exists", - pg_encoding_to_char(conforencoding), pg_encoding_to_char(contoencoding)); + pg_encoding_to_char(conforencoding), + pg_encoding_to_char(contoencoding)); } /* open pg_conversion */ @@ -96,10 +96,7 @@ ConversionCreate(const char *conname, Oid connamespace, values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding); values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding); values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc); - if (def == true) - values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def); - else - nulls[Anum_pg_conversion_condefault - 1] = 'n'; + values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def); tup = heap_formtuple(tupDesc, values, nulls); @@ -110,11 +107,11 @@ ConversionCreate(const char *conname, Oid connamespace, /* update the index if any */ CatalogUpdateIndexes(rel, tup); - myself.classId = get_system_catalog_relid(ConversionRelationName); + myself.classId = RelationGetRelid(rel); myself.objectId = HeapTupleGetOid(tup); myself.objectSubId = 0; - /* dependency on conversion procedure */ + /* create dependency on conversion procedure */ referenced.classId = RelOid_pg_proc; referenced.objectId = conproc; referenced.objectSubId = 0; @@ -126,79 +123,46 @@ ConversionCreate(const char *conname, Oid connamespace, return oid; } -/* ---------------- +/* * ConversionDrop * - * Drop a conversion and do dependency check. - * --------------- + * Drop a conversion after doing permission checks. */ void -ConversionDrop(const char *conname, Oid connamespace, - int32 conowner, DropBehavior behavior) +ConversionDrop(Oid conversionOid, DropBehavior behavior) { - Relation rel; - TupleDesc tupDesc; HeapTuple tuple; - HeapScanDesc scan; - ScanKeyData scanKeyData; - Form_pg_conversion body; ObjectAddress object; - Oid myoid; - - /* sanity checks */ - if (!conname) - elog(ERROR, "no conversion name supplied"); - - ScanKeyEntryInitialize(&scanKeyData, - 0, - Anum_pg_conversion_connamespace, - F_OIDEQ, - ObjectIdGetDatum(connamespace)); - - /* open pg_conversion */ - rel = heap_openr(ConversionRelationName, AccessShareLock); - tupDesc = rel->rd_att; - - scan = heap_beginscan(rel, SnapshotNow, - 1, &scanKeyData); - - /* search for the target tuple */ - while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) - { - body = (Form_pg_conversion) GETSTRUCT(tuple); - if (!strncmp(NameStr(body->conname), conname, NAMEDATALEN)) - break; - } + tuple = SearchSysCache(CONOID, + ObjectIdGetDatum(conversionOid), + 0, 0, 0); if (!HeapTupleIsValid(tuple)) - { - elog(ERROR, "conversion %s not found", conname); - return; - } + elog(ERROR, "Conversion %u search from syscache failed", + conversionOid); - if (!superuser() && ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId()) + if (!superuser() && + ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId()) elog(ERROR, "permission denied"); - myoid = HeapTupleGetOid(tuple); - heap_endscan(scan); - heap_close(rel, AccessShareLock); + ReleaseSysCache(tuple); /* * Do the deletion */ object.classId = get_system_catalog_relid(ConversionRelationName); - object.objectId = myoid; + object.objectId = conversionOid; object.objectSubId = 0; performDeletion(&object, behavior); } -/* ---------------- +/* * RemoveConversionById * - * Remove a tuple from pg_conversion by Oid. This function is soley + * Remove a tuple from pg_conversion by Oid. This function is solely * called inside catalog/dependency.c - * --------------- */ + */ void RemoveConversionById(Oid conversionOid) { @@ -230,15 +194,17 @@ RemoveConversionById(Oid conversionOid) heap_close(rel, RowExclusiveLock); } -/* ---------------- +/* * FindDefaultConversion * - * Find "default" conversion proc by for_encoding and to_encoding in this name space. - * If found, returns the procedure's oid, otherwise InvalidOid. - * --------------- + * Find "default" conversion proc by for_encoding and to_encoding in the + * given namespace. + * + * If found, returns the procedure's oid, otherwise InvalidOid. Note that + * you get the procedure's OID not the conversion's OID! */ Oid -FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) +FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding) { CatCList *catlist; HeapTuple tuple; @@ -246,10 +212,6 @@ FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) Oid proc = InvalidOid; int i; - /* Check we have usage rights in target namespace */ - if (pg_namespace_aclcheck(name_space, GetUserId(), ACL_USAGE) != ACLCHECK_OK) - return proc; - catlist = SearchSysCacheList(CONDEFAULT, 3, ObjectIdGetDatum(name_space), Int32GetDatum(for_encoding), @@ -260,7 +222,7 @@ FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) { tuple = &catlist->members[i]->tuple; body = (Form_pg_conversion) GETSTRUCT(tuple); - if (body->condefault == TRUE) + if (body->condefault) { proc = body->conproc; break; @@ -270,12 +232,11 @@ FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) return proc; } -/* ---------------- - * FindConversionByName +/* + * FindConversion * * Find conversion by namespace and conversion name. - * Returns conversion oid. - * --------------- + * Returns conversion OID. */ Oid FindConversion(const char *conname, Oid connamespace) @@ -286,13 +247,13 @@ FindConversion(const char *conname, Oid connamespace) AclResult aclresult; /* search pg_conversion by connamespace and conversion name */ - tuple = SearchSysCache(CONNAMESP, + tuple = SearchSysCache(CONNAMENSP, PointerGetDatum(conname), ObjectIdGetDatum(connamespace), 0, 0); - if (!HeapTupleIsValid(tuple)) return InvalidOid; + procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc; conoid = HeapTupleGetOid(tuple); diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index 614d3676c2..6115b0e12e 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.4 2002/09/04 20:31:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.5 2002/11/02 02:33:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,17 +38,14 @@ CreateConversionCommand(CreateConversionStmt *stmt) int for_encoding; int to_encoding; Oid funcoid; - Oid funcnamespace; - char *dummy; - const char *for_encoding_name = stmt->for_encoding_name; const char *to_encoding_name = stmt->to_encoding_name; List *func_name = stmt->func_name; - static Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, CSTRINGOID, INT4OID}; /* Convert list of names to a name and namespace */ - namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, &conversion_name); + namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, + &conversion_name); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); @@ -70,17 +67,13 @@ CreateConversionCommand(CreateConversionStmt *stmt) */ funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), funcargs); if (!OidIsValid(funcoid)) - elog(ERROR, "Function %s does not exist", NameListToString(func_name)); - - /* Check the rights for this function and name space */ - funcnamespace = QualifiedNameGetCreationNamespace(func_name, &dummy); - aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, get_namespace_name(funcnamespace)); + func_error("CreateConversion", func_name, + sizeof(funcargs) / sizeof(Oid), funcargs, NULL); + /* Check we have EXECUTE rights for the function */ aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, get_namespace_name(funcnamespace)); + aclcheck_error(aclresult, NameListToString(func_name)); /* * All seem ok, go ahead (possible failure would be a duplicate @@ -96,21 +89,12 @@ CreateConversionCommand(CreateConversionStmt *stmt) void DropConversionCommand(List *name, DropBehavior behavior) { - Oid namespaceId; - char *conversion_name; - AclResult aclresult; + Oid conversionOid; - /* Convert list of names to a name and namespace */ - namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name); + conversionOid = FindConversionByName(name); - /* Check we have creation rights in target namespace */ - aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, get_namespace_name(namespaceId)); + if (!OidIsValid(conversionOid)) + elog(ERROR, "conversion %s not found", NameListToString(name)); - /* - * Go ahead (possible failure would be: none existing conversion not - * ower of this conversion - */ - ConversionDrop(conversion_name, namespaceId, GetUserId(), behavior); + ConversionDrop(conversionOid, behavior); } diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h index 5c70e81238..47e01c5de3 100644 --- a/src/include/catalog/pg_conversion.h +++ b/src/include/catalog/pg_conversion.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_conversion.h,v 1.6 2002/09/04 20:31:37 momjian Exp $ + * $Id: pg_conversion.h,v 1.7 2002/11/02 02:33:03 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -85,12 +85,11 @@ typedef FormData_pg_conversion *Form_pg_conversion; extern Oid ConversionCreate(const char *conname, Oid connamespace, int32 conowner, - int4 conforencoding, int4 contoencoding, + int32 conforencoding, int32 contoencoding, Oid conproc, bool def); -extern void ConversionDrop(const char *conname, Oid connamespace, - int32 conowner, DropBehavior behavior); +extern void ConversionDrop(Oid conversionOid, DropBehavior behavior); extern void RemoveConversionById(Oid conversionOid); extern Oid FindConversion(const char *conname, Oid connamespace); -extern Oid FindDefaultConversion(Oid connamespace, int4 for_encoding, int4 to_encoding); +extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding); #endif /* PG_CONVERSION_H */ diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index def5ed5001..ff89f612c1 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: syscache.h,v 1.53 2002/09/04 20:31:46 momjian Exp $ + * $Id: syscache.h,v 1.54 2002/11/02 02:33:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -40,7 +40,7 @@ #define CLAAMNAMENSP 9 #define CLAOID 10 #define CONDEFAULT 11 -#define CONNAMESP 12 +#define CONNAMENSP 12 #define CONOID 13 #define GRONAME 14 #define GROSYSID 15