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.
This commit is contained in:
Tom Lane 2002-11-02 02:33:03 +00:00
parent 08dd92cdeb
commit 6a7273e14c
6 changed files with 86 additions and 148 deletions

View File

@ -1,4 +1,4 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_conversion.sgml,v 1.4 2002/09/21 18:32:54 petere Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_conversion.sgml,v 1.5 2002/11/02 02:33:03 tgl Exp $ -->
<refentry id="SQL-CREATECONVERSION"> <refentry id="SQL-CREATECONVERSION">
<refmeta> <refmeta>
@ -14,8 +14,7 @@
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable> CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
FOR <replaceable>source_encoding</replaceable> FOR <replaceable>source_encoding</replaceable> TO <replaceable>dest_encoding</replaceable> FROM <replaceable>funcname</replaceable>
TO <replaceable>dest_encoding</replaceable> FROM <replaceable>funcname</replaceable>
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -24,18 +23,16 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
<para> <para>
<command>CREATE CONVERSION</command> defines a new encoding <command>CREATE CONVERSION</command> defines a new encoding
conversion. There are two kinds of conversions. A default conversion. Conversion names may be used in the CONVERT() function
conversion is used for an automatic encoding conversion between to specify a particular encoding conversion. Also, conversions that
frontend and backend. There should be only one default conversion are marked DEFAULT can be used for automatic encoding conversion between
for source/destination encodings pair in a schema. None default frontend and backend. For this purpose, two conversions, from encoding A to
conversion never be used for the automatic conversion. Instead it B AND from encoding B to A, must be defined.
can be used for CONVERT() function.
</para> </para>
<para> <para>
To be able to create a conversion, you must have the execute right 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 on the function and the create right on the destination schema.
belongs to.
</para> </para>
<variablelist> <variablelist>
@ -49,11 +46,7 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
The <literal>DEFAULT</> clause indicates that this conversion The <literal>DEFAULT</> clause indicates that this conversion
is the default for this particular source to destination is the default for this particular source to destination
encoding. There should be only one default encoding in a schema encoding. There should be only one default encoding in a schema
for the encoding pair. A default encoding can be used for not for the encoding pair.
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.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -64,8 +57,8 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
<listitem> <listitem>
<para> <para>
The name of the conversion. The conversion name may be The name of the conversion. The conversion name may be
schema-qualified. If it is not, a conversion is defined in the schema-qualified. If it is not, the conversion is defined in the
current schema. The conversion name must be unique with in a current schema. The conversion name must be unique within a
schema. schema.
</para> </para>
</listitem> </listitem>
@ -102,7 +95,7 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
</para> </para>
<para> <para>
The function must have following signature: The function must have the following signature:
<programlisting> <programlisting>
conv_proc( conv_proc(

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 Oid
FindConversionByName(List *name) FindConversionByName(List *name)
{ {
char *schemaname;
char *conversion_name; char *conversion_name;
Oid namespaceId; Oid namespaceId;
Oid conoid; Oid conoid;
List *lptr; List *lptr;
/* Convert list of names to a name and namespace */ /* deconstruct the name list */
namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name); DeconstructQualifiedName(name, &schemaname, &conversion_name);
if (length(name) > 1) if (schemaname)
{ {
/* Check we have usage rights in target namespace */ /* use exact schema given */
if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK) namespaceId = LookupExplicitNamespace(schemaname);
return InvalidOid;
return FindConversion(conversion_name, namespaceId); return FindConversion(conversion_name, namespaceId);
} }
else
recomputeNamespacePath();
foreach(lptr, namespaceSearchPath)
{ {
Oid namespaceId = (Oid) lfirsti(lptr); /* search for it in search path */
recomputeNamespacePath();
conoid = FindConversion(conversion_name, namespaceId); foreach(lptr, namespaceSearchPath)
if (OidIsValid(conoid)) {
return conoid; namespaceId = (Oid) lfirsti(lptr);
conoid = FindConversion(conversion_name, namespaceId);
if (OidIsValid(conoid))
return conoid;
}
} }
/* Not found in path */ /* Not found in path */
@ -1308,7 +1309,7 @@ FindConversionByName(List *name)
} }
/* /*
* FindDefaultConversionProc - find default encoding cnnversion proc * FindDefaultConversionProc - find default encoding conversion proc
*/ */
Oid Oid
FindDefaultConversionProc(int4 for_encoding, int4 to_encoding) FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 "utils/acl.h"
#include "miscadmin.h" #include "miscadmin.h"
/* ---------------- /*
* ConversionCreate * ConversionCreate
* *
* Add a new tuple to pg_coversion. * Add a new tuple to pg_conversion.
* ---------------
*/ */
Oid Oid
ConversionCreate(const char *conname, Oid connamespace, ConversionCreate(const char *conname, Oid connamespace,
int32 conowner, int32 conowner,
int4 conforencoding, int4 contoencoding, int32 conforencoding, int32 contoencoding,
Oid conproc, bool def) Oid conproc, bool def)
{ {
int i; int i;
@ -58,7 +57,7 @@ ConversionCreate(const char *conname, Oid connamespace,
elog(ERROR, "no conversion name supplied"); elog(ERROR, "no conversion name supplied");
/* make sure there is no existing conversion of same name */ /* make sure there is no existing conversion of same name */
if (SearchSysCacheExists(CONNAMESP, if (SearchSysCacheExists(CONNAMENSP,
PointerGetDatum(conname), PointerGetDatum(conname),
ObjectIdGetDatum(connamespace), ObjectIdGetDatum(connamespace),
0, 0)) 0, 0))
@ -74,7 +73,8 @@ ConversionCreate(const char *conname, Oid connamespace,
conforencoding, conforencoding,
contoencoding)) contoencoding))
elog(ERROR, "default conversion for %s to %s already exists", 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 */ /* 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_conforencoding - 1] = Int32GetDatum(conforencoding);
values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding); values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc); values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
if (def == true) values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
else
nulls[Anum_pg_conversion_condefault - 1] = 'n';
tup = heap_formtuple(tupDesc, values, nulls); tup = heap_formtuple(tupDesc, values, nulls);
@ -110,11 +107,11 @@ ConversionCreate(const char *conname, Oid connamespace,
/* update the index if any */ /* update the index if any */
CatalogUpdateIndexes(rel, tup); CatalogUpdateIndexes(rel, tup);
myself.classId = get_system_catalog_relid(ConversionRelationName); myself.classId = RelationGetRelid(rel);
myself.objectId = HeapTupleGetOid(tup); myself.objectId = HeapTupleGetOid(tup);
myself.objectSubId = 0; myself.objectSubId = 0;
/* dependency on conversion procedure */ /* create dependency on conversion procedure */
referenced.classId = RelOid_pg_proc; referenced.classId = RelOid_pg_proc;
referenced.objectId = conproc; referenced.objectId = conproc;
referenced.objectSubId = 0; referenced.objectSubId = 0;
@ -126,79 +123,46 @@ ConversionCreate(const char *conname, Oid connamespace,
return oid; return oid;
} }
/* ---------------- /*
* ConversionDrop * ConversionDrop
* *
* Drop a conversion and do dependency check. * Drop a conversion after doing permission checks.
* ---------------
*/ */
void void
ConversionDrop(const char *conname, Oid connamespace, ConversionDrop(Oid conversionOid, DropBehavior behavior)
int32 conowner, DropBehavior behavior)
{ {
Relation rel;
TupleDesc tupDesc;
HeapTuple tuple; HeapTuple tuple;
HeapScanDesc scan;
ScanKeyData scanKeyData;
Form_pg_conversion body;
ObjectAddress object; 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)) if (!HeapTupleIsValid(tuple))
{ elog(ERROR, "Conversion %u search from syscache failed",
elog(ERROR, "conversion %s not found", conname); conversionOid);
return;
}
if (!superuser() && ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId()) if (!superuser() &&
((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId())
elog(ERROR, "permission denied"); elog(ERROR, "permission denied");
myoid = HeapTupleGetOid(tuple); ReleaseSysCache(tuple);
heap_endscan(scan);
heap_close(rel, AccessShareLock);
/* /*
* Do the deletion * Do the deletion
*/ */
object.classId = get_system_catalog_relid(ConversionRelationName); object.classId = get_system_catalog_relid(ConversionRelationName);
object.objectId = myoid; object.objectId = conversionOid;
object.objectSubId = 0; object.objectSubId = 0;
performDeletion(&object, behavior); performDeletion(&object, behavior);
} }
/* ---------------- /*
* RemoveConversionById * 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 * called inside catalog/dependency.c
* --------------- */ */
void void
RemoveConversionById(Oid conversionOid) RemoveConversionById(Oid conversionOid)
{ {
@ -230,15 +194,17 @@ RemoveConversionById(Oid conversionOid)
heap_close(rel, RowExclusiveLock); heap_close(rel, RowExclusiveLock);
} }
/* ---------------- /*
* FindDefaultConversion * FindDefaultConversion
* *
* Find "default" conversion proc by for_encoding and to_encoding in this name space. * Find "default" conversion proc by for_encoding and to_encoding in the
* If found, returns the procedure's oid, otherwise InvalidOid. * 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 Oid
FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
{ {
CatCList *catlist; CatCList *catlist;
HeapTuple tuple; HeapTuple tuple;
@ -246,10 +212,6 @@ FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
Oid proc = InvalidOid; Oid proc = InvalidOid;
int i; 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, catlist = SearchSysCacheList(CONDEFAULT, 3,
ObjectIdGetDatum(name_space), ObjectIdGetDatum(name_space),
Int32GetDatum(for_encoding), Int32GetDatum(for_encoding),
@ -260,7 +222,7 @@ FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
{ {
tuple = &catlist->members[i]->tuple; tuple = &catlist->members[i]->tuple;
body = (Form_pg_conversion) GETSTRUCT(tuple); body = (Form_pg_conversion) GETSTRUCT(tuple);
if (body->condefault == TRUE) if (body->condefault)
{ {
proc = body->conproc; proc = body->conproc;
break; break;
@ -270,12 +232,11 @@ FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
return proc; return proc;
} }
/* ---------------- /*
* FindConversionByName * FindConversion
* *
* Find conversion by namespace and conversion name. * Find conversion by namespace and conversion name.
* Returns conversion oid. * Returns conversion OID.
* ---------------
*/ */
Oid Oid
FindConversion(const char *conname, Oid connamespace) FindConversion(const char *conname, Oid connamespace)
@ -286,13 +247,13 @@ FindConversion(const char *conname, Oid connamespace)
AclResult aclresult; AclResult aclresult;
/* search pg_conversion by connamespace and conversion name */ /* search pg_conversion by connamespace and conversion name */
tuple = SearchSysCache(CONNAMESP, tuple = SearchSysCache(CONNAMENSP,
PointerGetDatum(conname), PointerGetDatum(conname),
ObjectIdGetDatum(connamespace), ObjectIdGetDatum(connamespace),
0, 0); 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
return InvalidOid; return InvalidOid;
procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc; procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
conoid = HeapTupleGetOid(tuple); conoid = HeapTupleGetOid(tuple);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 for_encoding;
int to_encoding; int to_encoding;
Oid funcoid; Oid funcoid;
Oid funcnamespace;
char *dummy;
const char *for_encoding_name = stmt->for_encoding_name; const char *for_encoding_name = stmt->for_encoding_name;
const char *to_encoding_name = stmt->to_encoding_name; const char *to_encoding_name = stmt->to_encoding_name;
List *func_name = stmt->func_name; List *func_name = stmt->func_name;
static Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, CSTRINGOID, INT4OID}; static Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, CSTRINGOID, INT4OID};
/* Convert list of names to a name and namespace */ /* 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 */ /* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
@ -70,17 +67,13 @@ CreateConversionCommand(CreateConversionStmt *stmt)
*/ */
funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), funcargs); funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), funcargs);
if (!OidIsValid(funcoid)) if (!OidIsValid(funcoid))
elog(ERROR, "Function %s does not exist", NameListToString(func_name)); func_error("CreateConversion", func_name,
sizeof(funcargs) / sizeof(Oid), funcargs, NULL);
/* 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));
/* Check we have EXECUTE rights for the function */
aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE); aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK) 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 * All seem ok, go ahead (possible failure would be a duplicate
@ -96,21 +89,12 @@ CreateConversionCommand(CreateConversionStmt *stmt)
void void
DropConversionCommand(List *name, DropBehavior behavior) DropConversionCommand(List *name, DropBehavior behavior)
{ {
Oid namespaceId; Oid conversionOid;
char *conversion_name;
AclResult aclresult;
/* Convert list of names to a name and namespace */ conversionOid = FindConversionByName(name);
namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name);
/* Check we have creation rights in target namespace */ if (!OidIsValid(conversionOid))
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); elog(ERROR, "conversion %s not found", NameListToString(name));
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_namespace_name(namespaceId));
/* ConversionDrop(conversionOid, behavior);
* Go ahead (possible failure would be: none existing conversion not
* ower of this conversion
*/
ConversionDrop(conversion_name, namespaceId, GetUserId(), behavior);
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * 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, extern Oid ConversionCreate(const char *conname, Oid connamespace,
int32 conowner, int32 conowner,
int4 conforencoding, int4 contoencoding, int32 conforencoding, int32 contoencoding,
Oid conproc, bool def); Oid conproc, bool def);
extern void ConversionDrop(const char *conname, Oid connamespace, extern void ConversionDrop(Oid conversionOid, DropBehavior behavior);
int32 conowner, DropBehavior behavior);
extern void RemoveConversionById(Oid conversionOid); extern void RemoveConversionById(Oid conversionOid);
extern Oid FindConversion(const char *conname, Oid connamespace); 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 */ #endif /* PG_CONVERSION_H */

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 CLAAMNAMENSP 9
#define CLAOID 10 #define CLAOID 10
#define CONDEFAULT 11 #define CONDEFAULT 11
#define CONNAMESP 12 #define CONNAMENSP 12
#define CONOID 13 #define CONOID 13
#define GRONAME 14 #define GRONAME 14
#define GROSYSID 15 #define GROSYSID 15