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">
<refmeta>
@ -14,8 +14,7 @@
<refsynopsisdiv>
<synopsis>
CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
FOR <replaceable>source_encoding</replaceable>
TO <replaceable>dest_encoding</replaceable> FROM <replaceable>funcname</replaceable>
FOR <replaceable>source_encoding</replaceable> TO <replaceable>dest_encoding</replaceable> FROM <replaceable>funcname</replaceable>
</synopsis>
</refsynopsisdiv>
@ -24,18 +23,16 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
<para>
<command>CREATE CONVERSION</command> 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.
</para>
<para>
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.
</para>
<variablelist>
@ -49,11 +46,7 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
The <literal>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.
</para>
</listitem>
</varlistentry>
@ -64,8 +57,8 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
<listitem>
<para>
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.
</para>
</listitem>
@ -102,7 +95,7 @@ CREATE [DEFAULT] CONVERSION <replaceable>conversion_name</replaceable>
</para>
<para>
The function must have following signature:
The function must have the following signature:
<programlisting>
conv_proc(

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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 */

View File

@ -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