Privileges on functions and procedural languages

This commit is contained in:
Peter Eisentraut 2002-02-18 23:11:58 +00:00
parent 5e03503126
commit 8adf56f77a
35 changed files with 2325 additions and 1534 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.29 2001/11/21 05:53:40 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.30 2002/02/18 23:10:59 petere Exp $
-->
<chapter id="catalogs">
@ -1261,6 +1261,13 @@
<entry></entry>
<entry>not currently used</entry>
</row>
<row>
<entry>lanacl</entry>
<entry><type>aclitem[]</type></entry>
<entry></entry>
<entry>Access permissions</entry>
</row>
</tbody>
</tgroup>
</table>
@ -1699,6 +1706,13 @@
Again, the interpretation is language-specific.
</entry>
</row>
<row>
<entry>proacl</entry>
<entry><type>aclitem[]</type></entry>
<entry></entry>
<entry>Access permissions</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.30 2001/12/08 03:24:34 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.31 2002/02/18 23:11:02 petere Exp $
-->
<refentry id="SQL-CREATEFUNCTION">
@ -270,6 +270,17 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
definition without breaking objects that refer to the function.
</para>
<para>
To be able to define a function, the user must have the
<literal>USAGE</literal> privilege on the language.
</para>
<para>
By default, only the owner (creator) of the function has the right
to execute it. Other users must be granted the
<literal>EXECUTE</literal> privilege on the function to be able to
use it.
</para>
</refsect1>
@ -369,7 +380,9 @@ Point * complex_to_point (Complex *z)
<para>
<xref linkend="sql-dropfunction">,
<xref linkend="sql-grant">,
<xref linkend="sql-load">,
<xref linkend="sql-revoke">,
<citetitle>PostgreSQL Programmer's Guide</citetitle>
</para>
</refsect1>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.20 2001/12/08 03:24:34 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.21 2002/02/18 23:11:02 petere Exp $
PostgreSQL documentation
-->
@ -203,8 +203,8 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
lanname | lanispl | lanpltrusted | lanplcallfoid | lancompiler
-------------+---------+--------------+---------------+-------------
internal | f | f | 0 | n/a
C | f | f | 0 | /bin/cc
sql | f | f | 0 | postgres
c | f | f | 0 | /bin/cc
sql | f | t | 0 | postgres
</screen>
</para>
@ -212,6 +212,13 @@ ERROR: PL handler function <replaceable class="parameter">funcname</replaceable
At present, the definition of a procedural language cannot be
changed once it has been created.
</para>
<para>
To be able to use a procedural language, a user must be granted the
<literal>USAGE</literal> privilege. The
<command>createlang</command> program automatically grants
permissions to everyone if the language is known to be trusted.
</para>
</refsect1>
<refsect1 id="sql-createlanguage-examples">
@ -257,6 +264,8 @@ CREATE LANGUAGE plsample
<member><xref linkend="sql-createfunction"></member>
<member><xref linkend="app-droplang"></member>
<member><xref linkend="sql-droplanguage"></member>
<member><xref linkend="sql-grant"></member>
<member><xref linkend="sql-revoke"></member>
<member><citetitle>PostgreSQL Programmer's Guide</citetitle></member>
</simplelist>
</para>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.19 2002/01/20 22:19:57 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.20 2002/02/18 23:11:02 petere Exp $
PostgreSQL documentation
-->
@ -19,6 +19,14 @@ PostgreSQL documentation
GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">objectname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE <replaceable>langname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
</synopsis>
</refsynopsisdiv>
@ -27,8 +35,9 @@ GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,..
<para>
The <command>GRANT</command> command gives specific permissions on
an object (table, view, sequence) to one or more users or groups of users.
These permissions are added to those already granted, if any.
an object (table, view, sequence, function, procedural language) to
one or more users or groups of users. These permissions are added
to those already granted, if any.
</para>
<para>
@ -134,14 +143,36 @@ GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,..
</listitem>
</varlistentry>
<varlistentry>
<term>EXECUTE</term>
<listitem>
<para>
Allows the use of the specified function and the use of any
operators that are implemented on top of the function. This is
the only type of privilege that is applicable to functions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>USAGE</term>
<listitem>
<para>
Allows the use of the specified procedural language for the
creation of functions in that language. This is the only type
of privilege that is applicable to procedural languages.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ALL PRIVILEGES</term>
<listitem>
<para>
Grant all of the above privileges at once. The
<literal>PRIVILEGES</literal> key word is optional in
<productname>PostgreSQL</productname>, though it is
required by strict SQL.
Grant all of the privileges applicable to the object at once.
The <literal>PRIVILEGES</literal> key word is optional in
<productname>PostgreSQL</productname>, though it is required by
strict SQL.
</para>
</listitem>
</varlistentry>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.19 2001/12/08 03:24:39 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.20 2002/02/18 23:11:03 petere Exp $
PostgreSQL documentation
-->
@ -19,6 +19,14 @@ PostgreSQL documentation
REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">object</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
REVOKE { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
REVOKE { USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE <replaceable>langname</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
</synopsis>
</refsynopsisdiv>

View File

@ -1,10 +1,35 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.115 2002/01/31 21:20:03 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.116 2002/02/18 23:11:00 petere Exp $
-->
<appendix id="release">
<title>Release Notes</title>
<sect1 id="release-devel">
<title>&version; Development Branch</title>
<para>
Below is a subset of the changes that have gone into the
development branch of PostgreSQL since version 7.2. For a complete
list of changes, consult the CVS logs.
</para>
<!--
Developers: When you add a feature, mention it here. This avoids
lossiness when digging out the information from the CVS logs, and
furthermore it advertises your feature to external parties at the
earliest possible moment.
CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
<literallayout><![CDATA[
Access privileges on functions
Access privileges on procedural languages
]]></literallayout>
</sect1>
<sect1 id="release-7-2">
<title>Release 7.2</title>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.53 2001/11/05 17:46:24 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.54 2002/02/18 23:11:07 petere Exp $
*
* NOTES
* See acl.h.
@ -18,22 +18,35 @@
#include "postgres.h"
#include "access/heapam.h"
#include "access/transam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_group.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/parsenodes.h"
#include "parser/keywords.h"
#include "parser/parse.h"
#include "parser/parse_agg.h"
#include "parser/parse_func.h"
#include "parser/parse_expr.h"
#include "utils/acl.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
static void ExecuteGrantStmt_Table(GrantStmt *stmt);
static void ExecuteGrantStmt_Function(GrantStmt *stmt);
static void ExecuteGrantStmt_Lang(GrantStmt *stmt);
static const char *privilege_token_string(int token);
static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
/* warning messages, now more explicit. */
@ -64,19 +77,128 @@ dumpacl(Acl *acl)
#endif /* ACLDEBUG */
/*
* If is_grant is true, adds the given privileges for the list of
* grantees to the existing old_acl. If is_grant is false, the
* privileges for the given grantees are removed from old_acl.
*/
static Acl*
merge_acl_with_grant(Acl *old_acl, bool is_grant, List *grantees, char *privileges)
{
List *j;
Acl *new_acl;
#ifdef ACLDEBUG
dumpacl(old_acl);
#endif
new_acl = old_acl;
foreach(j, grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
char *granteeString;
char *aclString;
AclItem aclitem;
unsigned modechg;
if (grantee->username)
granteeString = aclmakeuser("U", grantee->username);
else if (grantee->groupname)
granteeString = aclmakeuser("G", grantee->groupname);
else
granteeString = aclmakeuser("A", "");
aclString = makeAclString(privileges, granteeString,
is_grant ? '+' : '-');
/* Convert string ACL spec into internal form */
aclparse(aclString, &aclitem, &modechg);
new_acl = aclinsert3(new_acl, &aclitem, modechg);
#ifdef ACLDEBUG
dumpacl(new_acl);
#endif
}
return new_acl;
}
/*
* Called to execute the utility commands GRANT and REVOKE
*/
void
ExecuteGrantStmt(GrantStmt *stmt)
{
List *i;
List *j;
/* see comment in pg_type.h */
Assert(ACLITEMSIZE == sizeof(AclItem));
foreach(i, stmt->relnames)
switch(stmt->objtype)
{
case TABLE:
ExecuteGrantStmt_Table(stmt);
break;
case FUNCTION:
ExecuteGrantStmt_Function(stmt);
break;
case LANGUAGE:
ExecuteGrantStmt_Lang(stmt);
break;
default:
elog(ERROR, "bogus GrantStmt.objtype %d", stmt->objtype);
}
}
static void
ExecuteGrantStmt_Table(GrantStmt *stmt)
{
List *i;
char *privstring;
if (lfirsti(stmt->privileges) == ALL)
privstring = aclmakepriv(ACL_MODE_STR, 0);
else
{
privstring = "";
foreach(i, stmt->privileges)
{
int c = 0;
switch(lfirsti(i))
{
case SELECT:
c = ACL_MODE_SELECT_CHR;
break;
case INSERT:
c = ACL_MODE_INSERT_CHR;
break;
case UPDATE:
c = ACL_MODE_UPDATE_CHR;
break;
case DELETE:
c = ACL_MODE_DELETE_CHR;
break;
case RULE:
c = ACL_MODE_RULE_CHR;
break;
case REFERENCES:
c = ACL_MODE_REFERENCES_CHR;
break;
case TRIGGER:
c = ACL_MODE_TRIGGER_CHR;
break;
default:
elog(ERROR, "invalid privilege type %s for table object",
privilege_token_string(lfirsti(i)));
}
privstring = aclmakepriv(privstring, c);
}
}
foreach(i, stmt->objects)
{
char *relname = strVal(lfirst(i));
Relation relation;
@ -120,41 +242,13 @@ ExecuteGrantStmt(GrantStmt *stmt)
aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
&isNull);
if (isNull)
old_acl = acldefault(relname, pg_class_tuple->relowner);
old_acl = acldefault(pg_class_tuple->relowner);
else
/* get a detoasted copy of the rel's ACL */
old_acl = DatumGetAclPCopy(aclDatum);
#ifdef ACLDEBUG
dumpacl(old_acl);
#endif
new_acl = old_acl;
foreach(j, stmt->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
char *granteeString;
char *aclString;
AclItem aclitem;
unsigned modechg;
if (grantee->username)
granteeString = aclmakeuser("U", grantee->username);
else if (grantee->groupname)
granteeString = aclmakeuser("G", grantee->groupname);
else
granteeString = aclmakeuser("A", "");
aclString = makeAclString(stmt->privileges, granteeString,
stmt->is_grant ? '+' : '-');
/* Convert string ACL spec into internal form */
aclparse(aclString, &aclitem, &modechg);
new_acl = aclinsert3(new_acl, &aclitem, modechg);
#ifdef ACLDEBUG
dumpacl(new_acl);
#endif
}
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privstring);
/* finished building new ACL value, now insert it */
for (i = 0; i < Natts_pg_class; ++i)
@ -190,6 +284,267 @@ ExecuteGrantStmt(GrantStmt *stmt)
}
static Oid
find_function_with_arglist(char *name, List *arguments)
{
Oid oid;
Oid argoids[FUNC_MAX_ARGS];
int i;
int16 argcount;
MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));
argcount = length(arguments);
if (argcount > FUNC_MAX_ARGS)
elog(ERROR, "functions cannot have more than %d arguments",
FUNC_MAX_ARGS);
for (i = 0; i < argcount; i++)
{
TypeName *t = (TypeName *) lfirst(arguments);
char *typnam = TypeNameToInternalName(t);
arguments = lnext(arguments);
if (strcmp(typnam, "opaque") == 0)
argoids[i] = InvalidOid;
else
{
argoids[i] = GetSysCacheOid(TYPENAME,
PointerGetDatum(typnam),
0, 0, 0);
if (!OidIsValid(argoids[i]))
elog(ERROR, "type '%s' not found", typnam);
}
}
oid = GetSysCacheOid(PROCNAME,
PointerGetDatum(name),
Int16GetDatum(argcount),
PointerGetDatum(argoids),
0);
if (!OidIsValid(oid))
func_error(NULL, name, argcount, argoids, NULL);
return oid;
}
static void
ExecuteGrantStmt_Function(GrantStmt *stmt)
{
List *i;
char *privstring = NULL;
if (lfirsti(stmt->privileges) == ALL)
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
else
{
foreach(i, stmt->privileges)
{
if (lfirsti(i) != EXECUTE)
elog(ERROR, "invalid privilege type %s for function object",
privilege_token_string(lfirsti(i)));
}
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
}
foreach(i, stmt->objects)
{
FuncWithArgs *func = (FuncWithArgs *) lfirst(i);
Oid oid;
Relation relation;
HeapTuple tuple;
Form_pg_proc pg_proc_tuple;
Datum aclDatum;
bool isNull;
Acl *old_acl;
Acl *new_acl;
unsigned i;
HeapTuple newtuple;
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
char replaces[Natts_pg_proc];
oid = find_function_with_arglist(func->funcname, func->funcargs);
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0);
if (!HeapTupleIsValid(tuple))
{
heap_close(relation, RowExclusiveLock);
elog(ERROR, "function %u not found", oid);
}
pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
if (pg_proc_tuple->proowner != GetUserId())
elog(ERROR, "permission denied");
/*
* If there's no ACL, create a default using the pg_proc.proowner
* field.
*/
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
&isNull);
if (isNull)
old_acl = acldefault(pg_proc_tuple->proowner);
else
/* get a detoasted copy of the rel's ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privstring);
/* finished building new ACL value, now insert it */
for (i = 0; i < Natts_pg_proc; ++i)
{
replaces[i] = ' ';
nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
values[i] = (Datum) NULL; /* ignored if replaces[i]==' '
* anyway */
}
replaces[Anum_pg_proc_proacl - 1] = 'r';
values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
ReleaseSysCache(tuple);
simple_heap_update(relation, &newtuple->t_self, newtuple);
{
/* keep the catalog indexes up to date */
Relation idescs[Num_pg_proc_indices];
CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_proc_indices, relation, newtuple);
CatalogCloseIndices(Num_pg_proc_indices, idescs);
}
pfree(old_acl);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
}
}
static void
ExecuteGrantStmt_Lang(GrantStmt *stmt)
{
List *i;
char *privstring = NULL;
if (lfirsti(stmt->privileges) == ALL)
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
else
{
foreach(i, stmt->privileges)
{
if (lfirsti(i) != USAGE)
elog(ERROR, "invalid privilege type %s for language object",
privilege_token_string(lfirsti(i)));
}
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
}
foreach(i, stmt->objects)
{
char *langname = strVal(lfirst(i));
Relation relation;
HeapTuple tuple;
Form_pg_language pg_language_tuple;
Datum aclDatum;
bool isNull;
Acl *old_acl;
Acl *new_acl;
unsigned i;
HeapTuple newtuple;
Datum values[Natts_pg_language];
char nulls[Natts_pg_language];
char replaces[Natts_pg_language];
if (!superuser())
elog(ERROR, "permission denied");
relation = heap_openr(LanguageRelationName, RowExclusiveLock);
tuple = SearchSysCache(LANGNAME, PointerGetDatum(langname), 0, 0, 0);
if (!HeapTupleIsValid(tuple))
{
heap_close(relation, RowExclusiveLock);
elog(ERROR, "language \"%s\" not found", langname);
}
pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
if (!pg_language_tuple->lanpltrusted)
{
heap_close(relation, RowExclusiveLock);
elog(ERROR, "language \"%s\" is not trusted", langname);
}
/*
* If there's no ACL, create a default.
*/
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
&isNull);
if (isNull)
old_acl = acldefault(InvalidOid);
else
/* get a detoasted copy of the rel's ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privstring);
/* finished building new ACL value, now insert it */
for (i = 0; i < Natts_pg_language; ++i)
{
replaces[i] = ' ';
nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
values[i] = (Datum) NULL; /* ignored if replaces[i]==' '
* anyway */
}
replaces[Anum_pg_language_lanacl - 1] = 'r';
values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
ReleaseSysCache(tuple);
simple_heap_update(relation, &newtuple->t_self, newtuple);
{
/* keep the catalog indexes up to date */
Relation idescs[Num_pg_language_indices];
CatalogOpenIndices(Num_pg_language_indices, Name_pg_language_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_language_indices, relation, newtuple);
CatalogCloseIndices(Num_pg_language_indices, idescs);
}
pfree(old_acl);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
}
}
static const char *
privilege_token_string(int token)
{
const char *s = TokenString(token);
if (s)
return s;
else
elog(ERROR, "privilege_token_string: invalid token number");
return NULL; /* appease compiler */
}
AclId
get_grosysid(char *groname)
@ -483,7 +838,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
AclId ownerId;
ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
acl = acldefault(relname, ownerId);
acl = acldefault(ownerId);
aclDatum = (Datum) 0;
}
else
@ -721,3 +1076,142 @@ pg_aggr_ownercheck(Oid userid,
return userid == owner_id;
}
/*
* Exported routine for checking a user's access privileges to a function
*
* Returns an ACLCHECK_* result code.
*/
int32
pg_proc_aclcheck(Oid proc_oid, Oid userid)
{
int32 result;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
if (superuser_arg(userid))
return ACLCHECK_OK;
/*
* Validate userid
*/
tuple = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(userid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_proc_aclcheck: invalid user id %u",
(unsigned) userid);
ReleaseSysCache(tuple);
/*
* Normal case: get the function's ACL from pg_proc
*/
tuple = SearchSysCache(PROCOID,
ObjectIdGetDatum(proc_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_proc_aclcheck: function %u not found", proc_oid);
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
&isNull);
if (isNull)
{
/* No ACL, so build default ACL */
AclId ownerId;
ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
acl = acldefault(ownerId);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
/*
* Functions only have one kind of privilege, which is encoded as
* "SELECT" here.
*/
result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
ReleaseSysCache(tuple);
return result;
}
/*
* Exported routine for checking a user's access privileges to a language
*
* Returns an ACLCHECK_* result code.
*/
int32
pg_language_aclcheck(Oid lang_oid, Oid userid)
{
int32 result;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
if (superuser_arg(userid))
return ACLCHECK_OK;
/*
* Validate userid
*/
tuple = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(userid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_language_aclcheck: invalid user id %u",
(unsigned) userid);
ReleaseSysCache(tuple);
/*
* Normal case: get the function's ACL from pg_language
*/
tuple = SearchSysCache(LANGOID,
ObjectIdGetDatum(lang_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_language_aclcheck: language %u not found", lang_oid);
aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
&isNull);
if (isNull)
{
/* No ACL, so build default ACL */
acl = acldefault(InvalidOid);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
/*
* Languages only have one kind of privilege, which is encoded as
* "SELECT" here.
*/
result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
ReleaseSysCache(tuple);
return result;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.63 2001/11/05 17:46:24 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.64 2002/02/18 23:11:08 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -44,7 +44,7 @@ ProcedureCreate(char *procedureName,
bool replace,
bool returnsSet,
char *returnTypeName,
char *languageName,
Oid languageObjectId,
char *prosrc,
char *probin,
bool trusted,
@ -65,7 +65,6 @@ ProcedureCreate(char *procedureName,
char nulls[Natts_pg_proc];
Datum values[Natts_pg_proc];
char replaces[Natts_pg_proc];
Oid languageObjectId;
Oid typeObjectId;
List *x;
List *querytree_list;
@ -82,12 +81,6 @@ ProcedureCreate(char *procedureName,
Assert(PointerIsValid(prosrc));
Assert(PointerIsValid(probin));
languageObjectId = GetSysCacheOid(LANGNAME,
PointerGetDatum(languageName),
0, 0, 0);
if (!OidIsValid(languageObjectId))
elog(ERROR, "language '%s' does not exist", languageName);
parameterCount = 0;
MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
foreach(x, argList)
@ -320,6 +313,9 @@ ProcedureCreate(char *procedureName,
elog(ERROR, "ProcedureCreate: cannot change return type of existing function."
"\n\tUse DROP FUNCTION first.");
/* do not change existing permissions */
replaces[Anum_pg_proc_proacl-1] = ' ';
/* Okay, do it... */
tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
simple_heap_update(rel, &tup->t_self, tup);
@ -329,6 +325,10 @@ ProcedureCreate(char *procedureName,
else
{
/* Creating a new procedure */
/* start out with empty permissions */
nulls[Anum_pg_proc_proacl-1] = 'n';
tup = heap_formtuple(tupDesc, values, nulls);
heap_insert(rel, tup);
}

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.64 2001/10/28 06:25:42 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.65 2002/02/18 23:11:10 petere Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -50,6 +50,7 @@
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "parser/parse_expr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
@ -60,22 +61,18 @@ static int defGetTypeLength(DefElem *def);
#define DEFAULT_TYPDELIM ','
/*
* Translate the input language name to lower case.
*/
static void
case_translate_language_name(const char *input, char *output)
{
/*
* Translate the input language name to lower case, except if it's "C",
* translate to upper case.
*/
int i;
for (i = 0; i < NAMEDATALEN - 1 && input[i]; ++i)
output[i] = tolower((unsigned char) input[i]);
output[i] = '\0';
if (strcmp(output, "c") == 0)
output[0] = 'C';
}
@ -175,12 +172,12 @@ compute_full_attributes(List *parameters,
*/
static void
interpret_AS_clause(const char *languageName, const List *as,
interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
char **prosrc_str_p, char **probin_str_p)
{
Assert(as != NIL);
if (strcmp(languageName, "C") == 0)
if (languageOid == ClanguageId)
{
/*
* For "C" language, store the file name in probin and, when
@ -213,29 +210,16 @@ interpret_AS_clause(const char *languageName, const List *as,
void
CreateFunction(ProcedureStmt *stmt)
{
char *probin_str;
/* pathname of executable file that executes this function, if any */
char *prosrc_str;
char *probin_str;
/* SQL that executes this function, if any */
char *prorettype;
char *prosrc_str;
/* Type of return value (or member of set of values) from function */
char *prorettype;
/* name of language of function, with case adjusted */
char languageName[NAMEDATALEN];
/*
* name of language of function, with case adjusted: "C", "internal",
* "sql", etc.
*/
bool returnsSet;
/* The function returns a set of values, as opposed to a singleton. */
bool returnsSet;
/*
* The following are optional user-supplied attributes of the
* function.
@ -247,62 +231,28 @@ CreateFunction(ProcedureStmt *stmt)
bool canCache,
isStrict;
HeapTuple languageTuple;
Form_pg_language languageStruct;
Oid languageOid;
/* Convert language name to canonical case */
case_translate_language_name(stmt->language, languageName);
/*
* Apply appropriate security checks depending on language.
*/
if (strcmp(languageName, "C") == 0 ||
strcmp(languageName, "internal") == 0)
{
if (!superuser())
elog(ERROR,
"Only users with Postgres superuser privilege are "
"permitted to create a function in the '%s' language.\n\t"
"Others may use the 'sql' language "
"or the created procedural languages.",
languageName);
}
else if (strcmp(languageName, "sql") == 0)
{
/* No security check needed for SQL functions */
}
else
{
HeapTuple languageTuple;
Form_pg_language languageStruct;
languageTuple = SearchSysCache(LANGNAME,
PointerGetDatum(languageName),
0, 0, 0);
if (!HeapTupleIsValid(languageTuple))
elog(ERROR, "language \"%s\" does not exist", languageName);
/* Lookup the language in the system cache */
languageTuple = SearchSysCache(LANGNAME,
PointerGetDatum(languageName),
0, 0, 0);
if (!HeapTupleIsValid(languageTuple))
elog(ERROR,
"Unrecognized language specified in a CREATE FUNCTION: "
"'%s'.\n\tPre-installed languages are SQL, C, and "
"internal.\n\tAdditional languages may be installed "
"using 'createlang'.",
languageName);
languageOid = languageTuple->t_data->t_oid;
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
/* Check that this language is a PL */
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
if (!languageStruct->lanispl)
elog(ERROR,
"Language '%s' isn't defined as PL", languageName);
if (!((languageStruct->lanpltrusted
&& pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK)
|| superuser()))
elog(ERROR, "permission denied");
/*
* Functions in untrusted procedural languages are restricted to
* be defined by postgres superusers only
*/
if (!languageStruct->lanpltrusted && !superuser())
elog(ERROR, "Only users with Postgres superuser privilege "
"are permitted to create a function in the '%s' "
"language.",
languageName);
ReleaseSysCache(languageTuple);
}
ReleaseSysCache(languageTuple);
/*
* Convert remaining parameters of CREATE to form wanted by
@ -316,7 +266,7 @@ CreateFunction(ProcedureStmt *stmt)
&byte_pct, &perbyte_cpu, &percall_cpu,
&outin_ratio, &canCache, &isStrict);
interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
interpret_AS_clause(languageOid, languageName, stmt->as, &prosrc_str, &probin_str);
/*
* And now that we have all the parameters, and know we're permitted
@ -326,7 +276,7 @@ CreateFunction(ProcedureStmt *stmt)
stmt->replace,
returnsSet,
prorettype,
languageName,
languageOid,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
true, /* (obsolete "trusted") */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.28 2001/06/13 21:44:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.29 2002/02/18 23:11:11 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -27,22 +27,18 @@
#include "utils/syscache.h"
/*
* Translate the input language name to lower case.
*/
static void
case_translate_language_name(const char *input, char *output)
{
/*-------------------------------------------------------------------------
Translate the input language name to lower case, except if it's C,
translate to upper case.
--------------------------------------------------------------------------*/
int i;
for (i = 0; i < NAMEDATALEN && input[i]; ++i)
output[i] = tolower((unsigned char) input[i]);
output[i] = '\0';
if (strcmp(output, "c") == 0)
output[0] = 'C';
}
@ -116,6 +112,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
values[i++] = ObjectIdGetDatum(procTup->t_data->t_oid);
values[i++] = DirectFunctionCall1(textin,
CStringGetDatum(stmt->plcompiler));
nulls[i] = 'n'; /* lanacl */
ReleaseSysCache(procTup);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.89 2001/10/25 05:49:27 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.90 2002/02/18 23:11:13 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -658,6 +658,9 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
bool hasSetArg;
int i;
if (!fcache->permission_ok)
elog(ERROR, "permission denied");
/*
* arguments is a list of expressions to evaluate before passing to
* the function manager. We skip the evaluation if it was already

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.160 2001/11/05 05:00:14 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.161 2002/02/18 23:11:14 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -1893,9 +1893,9 @@ _copyGrantStmt(GrantStmt *from)
GrantStmt *newnode = makeNode(GrantStmt);
newnode->is_grant = from->is_grant;
Node_Copy(from, newnode, relnames);
if (from->privileges)
newnode->privileges = pstrdup(from->privileges);
newnode->objtype = from->objtype;
Node_Copy(from, newnode, objects);
Node_Copy(from, newnode, privileges);
Node_Copy(from, newnode, grantees);
return newnode;
@ -1914,6 +1914,20 @@ _copyPrivGrantee(PrivGrantee *from)
return newnode;
}
static FuncWithArgs *
_copyFuncWithArgs(FuncWithArgs *from)
{
FuncWithArgs *newnode = makeNode(FuncWithArgs);
if (from->funcname)
newnode->funcname = pstrdup(from->funcname);
else
newnode->funcname = NULL;
Node_Copy(from, newnode, funcargs);
return newnode;
}
static ClosePortalStmt *
_copyClosePortalStmt(ClosePortalStmt *from)
{
@ -2971,6 +2985,9 @@ copyObject(void *from)
case T_PrivGrantee:
retval = _copyPrivGrantee(from);
break;
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
break;
default:
elog(ERROR, "copyObject: don't know how to copy node type %d",

View File

@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.108 2001/11/05 05:00:14 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.109 2002/02/18 23:11:14 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -758,9 +758,11 @@ _equalGrantStmt(GrantStmt *a, GrantStmt *b)
{
if (a->is_grant != b->is_grant)
return false;
if (!equal(a->relnames, b->relnames))
if (a->objtype != b->objtype)
return false;
if (!equalstr(a->privileges, b->privileges))
if (!equal(a->objects, b->objects))
return false;
if (!equal(a->privileges, b->privileges))
return false;
if (!equal(a->grantees, b->grantees))
return false;
@ -775,6 +777,13 @@ _equalPrivGrantee(PrivGrantee *a, PrivGrantee *b)
&& equalstr(a->groupname, b->groupname);
}
static bool
_equalFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b)
{
return equalstr(a->funcname, b->funcname)
&& equal(a->funcargs, b->funcargs);
}
static bool
_equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
{
@ -2122,6 +2131,9 @@ equal(void *a, void *b)
case T_PrivGrantee:
retval = _equalPrivGrantee(a, b);
break;
case T_FuncWithArgs:
retval = _equalFuncWithArgs(a, b);
break;
default:
elog(NOTICE, "equal: don't know whether nodes of type %d are equal",

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.277 2002/02/18 06:49:20 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.278 2002/02/18 23:11:17 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -56,7 +56,6 @@
#include "nodes/parsenodes.h"
#include "parser/gramparse.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/numeric.h"
#include "utils/datetime.h"
@ -122,6 +121,7 @@ static void doNegateFloat(Value *v);
A_Indices *aind;
ResTarget *target;
ParamNo *paramno;
PrivTarget *privtarget;
VersionStmt *vstmt;
DefineStmt *dstmt;
@ -182,10 +182,14 @@ static void doNegateFloat(Value *v);
OptUseOp, opt_class, SpecialRuleRelation
%type <str> opt_level, opt_encoding
%type <str> privileges, operation_commalist
%type <node> grantee
%type <list> grantee_list
%type <chr> operation, TriggerOneEvent
%type <ival> privilege
%type <list> privileges, privilege_list
%type <privtarget> privilege_target
%type <node> function_with_argtypes
%type <list> function_with_argtypes_list
%type <chr> TriggerOneEvent
%type <list> stmtblock, stmtmulti,
into_clause, OptTempTableName, relation_name_list,
@ -323,7 +327,7 @@ static void doNegateFloat(Value *v);
SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING,
TABLE, TEMPORARY, THEN, TIME, TIMESTAMP,
TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING,
UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UPDATE, USAGE, USER, USING,
VALUES, VARCHAR, VARYING, VIEW,
WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
@ -2327,73 +2331,94 @@ from_in: IN
/*****************************************************************************
*
* GRANT privileges ON [TABLE] relation_name_list TO [GROUP] grantee, ...
* GRANT and REVOKE statements
*
*****************************************************************************/
GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee_list opt_with_grant
GrantStmt: GRANT privileges ON privilege_target TO grantee_list opt_grant_grant_option
{
GrantStmt *n = makeNode(GrantStmt);
n->is_grant = true;
n->relnames = $5;
n->privileges = $2;
n->grantees = $7;
n->objtype = ($4)->objtype;
n->objects = ($4)->objs;
n->grantees = $6;
$$ = (Node*)n;
}
;
privileges: ALL PRIVILEGES
RevokeStmt: REVOKE opt_revoke_grant_option privileges ON privilege_target FROM grantee_list
{
$$ = aclmakepriv(ACL_MODE_STR,0);
}
| ALL
{
$$ = aclmakepriv(ACL_MODE_STR,0);
}
| operation_commalist
{
$$ = $1;
GrantStmt *n = makeNode(GrantStmt);
n->is_grant = false;
n->privileges = $3;
n->objtype = ($5)->objtype;
n->objects = ($5)->objs;
n->grantees = $7;
$$ = (Node *)n;
}
;
operation_commalist: operation
/* either ALL [PRIVILEGES] or a list of individual privileges */
privileges: privilege_list { $$ = $1; }
| ALL { $$ = makeListi1(ALL); }
| ALL PRIVILEGES { $$ = makeListi1(ALL); }
;
privilege_list: privilege { $$ = makeListi1($1); }
| privilege_list ',' privilege { $$ = lappendi($1, $3); }
;
/* Not all of these privilege types apply to all objects, but that
gets sorted out later. */
privilege: SELECT { $$ = SELECT; }
| INSERT { $$ = INSERT; }
| UPDATE { $$ = UPDATE; }
| DELETE { $$ = DELETE; }
| RULE { $$ = RULE; }
| REFERENCES { $$ = REFERENCES; }
| TRIGGER { $$ = TRIGGER; }
| EXECUTE { $$ = EXECUTE; }
| USAGE { $$ = USAGE; }
;
/* Don't bother trying to fold the first two rules into one using
opt_table. You're going to get conflicts. */
privilege_target: relation_name_list
{
$$ = aclmakepriv("",$1);
PrivTarget *n = makeNode(PrivTarget);
n->objtype = TABLE;
n->objs = $1;
$$ = n;
}
| operation_commalist ',' operation
| TABLE relation_name_list
{
$$ = aclmakepriv($1,$3);
PrivTarget *n = makeNode(PrivTarget);
n->objtype = TABLE;
n->objs = $2;
$$ = n;
}
| FUNCTION function_with_argtypes_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = FUNCTION;
n->objs = $2;
$$ = n;
}
| LANGUAGE name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = LANGUAGE;
n->objs = $2;
$$ = n;
}
;
operation: SELECT
{
$$ = ACL_MODE_SELECT_CHR;
}
| INSERT
{
$$ = ACL_MODE_INSERT_CHR;
}
| UPDATE
{
$$ = ACL_MODE_UPDATE_CHR;
}
| DELETE
{
$$ = ACL_MODE_DELETE_CHR;
}
| RULE
{
$$ = ACL_MODE_RULE_CHR;
}
| REFERENCES
{
$$ = ACL_MODE_REFERENCES_CHR;
}
| TRIGGER
{
$$ = ACL_MODE_TRIGGER_CHR;
}
grantee_list: grantee { $$ = makeList1($1); }
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
grantee: PUBLIC
@ -2419,31 +2444,33 @@ grantee: PUBLIC
}
;
grantee_list: grantee { $$ = makeList1($1); }
| grantee_list ',' grantee { $$ = lappend($1, $3); }
opt_with_grant: WITH GRANT OPTION
opt_grant_grant_option: WITH GRANT OPTION
{
elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges");
}
elog(ERROR, "grant options are not implemented");
}
| /*EMPTY*/
;
opt_revoke_grant_option: GRANT OPTION FOR
{
elog(ERROR, "grant options are not implemented");
}
| /*EMPTY*/
;
/*****************************************************************************
*
* REVOKE privileges ON [TABLE] relation_name_list FROM user, ...
*
*****************************************************************************/
function_with_argtypes_list: function_with_argtypes
{ $$ = makeList1($1); }
| function_with_argtypes_list ',' function_with_argtypes
{ $$ = lappend($1, $3); }
;
RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
function_with_argtypes: func_name func_args
{
GrantStmt *n = makeNode(GrantStmt);
n->is_grant = false;
n->relnames = $5;
n->privileges = $2;
n->grantees = $7;
FuncWithArgs *n = makeNode(FuncWithArgs);
n->funcname = $1;
n->funcargs = $2;
$$ = (Node *)n;
}
;
@ -5876,6 +5903,7 @@ unreserved_keyword:
| UNLISTEN { $$ = "unlisten"; }
| UNTIL { $$ = "until"; }
| UPDATE { $$ = "update"; }
| USAGE { $$ = "usage"; }
| VACUUM { $$ = "vacuum"; }
| VALID { $$ = "valid"; }
| VALUES { $$ = "values"; }

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.99 2001/10/10 00:02:42 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.100 2002/02/18 23:11:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -269,6 +269,7 @@ static ScanKeyword ScanKeywords[] = {
{"unlisten", UNLISTEN},
{"until", UNTIL},
{"update", UPDATE},
{"usage", USAGE},
{"user", USER},
{"using", USING},
{"vacuum", VACUUM},
@ -354,3 +355,36 @@ ScanKeywordLookup(char *text)
return NULL;
}
/*
* This does the reverse mapping from token number to string.
*/
const char *
TokenString(int token)
{
int i = 0;
static char buf[NAMEDATALEN];
while (i < sizeof(ScanKeywords))
{
if (ScanKeywords[i].value == token)
{
int k;
/* uppercase */
for (k = 0; k < NAMEDATALEN; k++)
if (ScanKeywords[i].name[k] >= 'a'
&& ScanKeywords[i].name[k] <= 'z')
buf[k] = ScanKeywords[i].name[k] + ('A' - 'a');
else
buf[k] = ScanKeywords[i].name[k];
return buf;
}
i++;
}
return NULL;
}

View File

@ -9,7 +9,7 @@
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.20 2001/05/22 12:06:51 momjian Exp $
# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.21 2002/02/18 23:11:20 petere Exp $
#
#-------------------------------------------------------------------------
@ -164,7 +164,7 @@ FuNkYfMgRsTuFf
tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $RAWFILE | \
$AWK '
BEGIN { OFS = ""; }
{ if (seenit[$(NF-1)]++ == 0) print "#define F_", $(NF-1), " ", $1; }' >> "$$-$OIDSFILE"
{ if (seenit[$(NF-2)]++ == 0) print "#define F_", $(NF-2), " ", $1; }' >> "$$-$OIDSFILE"
if [ $? -ne 0 ]; then
cleanup
@ -209,7 +209,7 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
FuNkYfMgRtAbStUfF
$AWK '{ print "extern Datum", $(NF-1), "(PG_FUNCTION_ARGS);"; }' $RAWFILE >> "$$-$TABLEFILE"
$AWK '{ print "extern Datum", $(NF-2), "(PG_FUNCTION_ARGS);"; }' $RAWFILE >> "$$-$TABLEFILE"
if [ $? -ne 0 ]; then
cleanup
@ -232,7 +232,7 @@ $AWK 'BEGIN {
Bool["f"] = "false"
}
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
$1, $(NF-1), $9, Bool[$8], Bool[$10], $(NF-1)
$1, $(NF-2), $9, Bool[$8], Bool[$10], $(NF-2)
}' $RAWFILE >> "$$-$TABLEFILE"
if [ $? -ne 0 ]; then

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.66 2001/11/16 23:30:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.67 2002/02/18 23:11:22 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -373,7 +373,7 @@ aclitemgt(const AclItem *a1, const AclItem *a2)
* newly-created tables (or any table with a NULL acl entry in pg_class)
*/
Acl *
acldefault(const char *relname, AclId ownerid)
acldefault(AclId ownerid)
{
Acl *acl;
AclItem *aip;
@ -381,16 +381,18 @@ acldefault(const char *relname, AclId ownerid)
#define ACL_WORLD_DEFAULT (ACL_NO)
#define ACL_OWNER_DEFAULT (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
acl = makeacl(2);
acl = makeacl(ownerid ? 2 : 1);
aip = ACL_DAT(acl);
aip[0].ai_idtype = ACL_IDTYPE_WORLD;
aip[0].ai_id = ACL_ID_WORLD;
aip[0].ai_mode = (IsSystemRelationName(relname) &&
!IsToastRelationName(relname)) ? ACL_SELECT
: ACL_WORLD_DEFAULT;
aip[1].ai_idtype = ACL_IDTYPE_UID;
aip[1].ai_id = ownerid;
aip[1].ai_mode = ACL_OWNER_DEFAULT;
aip[0].ai_mode = ACL_WORLD_DEFAULT;
/* FIXME: The owner's default should vary with the object type. */
if (ownerid)
{
aip[1].ai_idtype = ACL_IDTYPE_UID;
aip[1].ai_id = ownerid;
aip[1].ai_mode = ACL_OWNER_DEFAULT;
}
return acl;
}

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.39 2001/10/02 21:39:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.40 2002/02/18 23:11:23 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,6 +20,7 @@
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "executor/executor.h"
#include "utils/fcache.h"
@ -54,7 +55,7 @@ SetDefine(char *querystr, char *typename)
false, /* don't replace */
true, /* returnsSet */
typename, /* returnTypeName */
"sql", /* languageName */
SQLlanguageId, /* language */
querystr, /* sourceCode */
fileName, /* fileName */
true, /* trusted */

View File

@ -8,12 +8,14 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.41 2001/10/06 23:21:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.42 2002/02/18 23:11:25 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/fcache.h"
@ -40,5 +42,7 @@ init_fcache(Oid foid, int nargs, MemoryContext fcacheCxt)
/* Initialize additional info */
retval->setArgsValid = false;
retval->permission_ok = pg_proc_aclcheck(foid, GetUserId()) == ACLCHECK_OK;
return retval;
}

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.19 2001/09/08 15:24:00 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.20 2002/02/18 23:11:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,16 +30,23 @@
*/
bool
superuser(void)
{
return superuser_arg(GetUserId());
}
bool
superuser_arg(Oid userid)
{
bool result = false;
HeapTuple utup;
/* Special escape path in case you deleted all your users. */
if (!IsUnderPostmaster && GetUserId() == BOOTSTRAP_USESYSID)
if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID)
return true;
utup = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(GetUserId()),
ObjectIdGetDatum(userid),
0, 0, 0);
if (HeapTupleIsValid(utup))
{
@ -49,6 +56,7 @@ superuser(void)
return result;
}
/*
* The Postgres user running this command is the owner of the specified
* database.

View File

@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.142 2001/11/25 22:19:30 petere Exp $
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.143 2002/02/18 23:11:28 petere Exp $
#
#-------------------------------------------------------------------------
@ -833,6 +833,24 @@ EOF
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "ok"
# Set most system catalogs and built-in functions as world-accessible.
# Some objects may require different permissions by default, so we
# make sure we don't overwrite privilege sets that have already been
# set (NOT NULL).
$ECHO_N "setting privileges on built-in objects... "$ECHO_C
(
cat <<EOF
UPDATE pg_class SET relacl = '{"=r"}' \
WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;
UPDATE pg_proc SET proacl = '{"=r"}' \
WHERE proacl IS NULL;
UPDATE pg_language SET lanacl = '{"=r"}' \
WHERE lanpltrusted;
EOF
) \
| "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "ok"
$ECHO_N "vacuuming database template1... "$ECHO_C
"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF

View File

@ -7,7 +7,7 @@
# Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.33 2002/02/18 05:48:44 momjian Exp $
# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.34 2002/02/18 23:11:30 petere Exp $
#
#-------------------------------------------------------------------------
@ -289,4 +289,15 @@ if [ "$?" -ne 0 ]; then
exit 1
fi
if test -n "$trusted"; then
sqlcmd="GRANT USAGE ON LANGUAGE \"$langname\" TO PUBLIC;"
if [ "$showsql" = yes ]; then
echo "$sqlcmd"
fi
$PSQL "$sqlcmd"
if [ "$?" -ne 0 ]; then
echo "$CMDNAME: language installation failed" 1>&2
exit 1
fi
fi
exit 0

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.103 2002/01/12 18:09:04 tgl Exp $
* $Id: catversion.h,v 1.104 2002/02/18 23:11:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200201121
#define CATALOG_VERSION_NO 200202181
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_attribute.h,v 1.79 2001/11/05 17:46:32 momjian Exp $
* $Id: pg_attribute.h,v 1.80 2002/02/18 23:11:33 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -310,7 +310,8 @@ DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p f i f f));
{ 1255, {"propercall_cpu"}, 23, 0, 4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
{ 1255, {"prooutin_ratio"}, 23, 0, 4, 15, 0, -1, -1, true, 'p', false, 'i', false, false }, \
{ 1255, {"prosrc"}, 25, 0, -1, 16, 0, -1, -1, false, 'x', false, 'i', false, false }, \
{ 1255, {"probin"}, 17, 0, -1, 17, 0, -1, -1, false, 'x', false, 'i', false, false }
{ 1255, {"probin"}, 17, 0, -1, 17, 0, -1, -1, false, 'x', false, 'i', false, false }, \
{ 1255, {"proacl"}, 1034, 0, -1, 18, 0, -1, -1, false, 'x', false, 'i', false, false }
DATA(insert ( 1255 proname 19 DEFAULT_ATTSTATTARGET NAMEDATALEN 1 0 -1 -1 f p f i f f));
DATA(insert ( 1255 proowner 23 0 4 2 0 -1 -1 t p f i f f));
@ -329,6 +330,7 @@ DATA(insert ( 1255 propercall_cpu 23 0 4 14 0 -1 -1 t p f i f f));
DATA(insert ( 1255 prooutin_ratio 23 0 4 15 0 -1 -1 t p f i f f));
DATA(insert ( 1255 prosrc 25 0 -1 16 0 -1 -1 f x f i f f));
DATA(insert ( 1255 probin 17 0 -1 17 0 -1 -1 f x f i f f));
DATA(insert ( 1255 proacl 1034 0 -1 18 0 -1 -1 f x f i f f));
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p f i f f));
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p f i f f));
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p f i f f));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_class.h,v 1.57 2001/11/05 17:46:32 momjian Exp $
* $Id: pg_class.h,v 1.58 2002/02/18 23:11:34 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -136,7 +136,7 @@ DATA(insert OID = 1247 ( pg_type 71 PGUID 0 1247 0 0 0 0 f f r 17 0 0 0 0 0 t
DESCR("");
DATA(insert OID = 1249 ( pg_attribute 75 PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
DESCR("");
DATA(insert OID = 1255 ( pg_proc 81 PGUID 0 1255 0 0 0 0 f f r 17 0 0 0 0 0 t f f f _null_ ));
DATA(insert OID = 1255 ( pg_proc 81 PGUID 0 1255 0 0 0 0 f f r 18 0 0 0 0 0 t f f f _null_ ));
DESCR("");
DATA(insert OID = 1259 ( pg_class 83 PGUID 0 1259 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ ));
DESCR("");

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_language.h,v 1.15 2001/11/05 17:46:32 momjian Exp $
* $Id: pg_language.h,v 1.16 2002/02/18 23:11:35 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -38,6 +38,7 @@ CATALOG(pg_language)
bool lanpltrusted; /* PL is trusted */
Oid lanplcallfoid; /* Call handler for PL */
text lancompiler; /* VARIABLE LENGTH FIELD */
aclitem lanacl[1]; /* Access privileges */
} FormData_pg_language;
/* ----------------
@ -51,25 +52,26 @@ typedef FormData_pg_language *Form_pg_language;
* compiler constants for pg_language
* ----------------
*/
#define Natts_pg_language 5
#define Natts_pg_language 6
#define Anum_pg_language_lanname 1
#define Anum_pg_language_lanispl 2
#define Anum_pg_language_lanpltrusted 3
#define Anum_pg_language_lanplcallfoid 4
#define Anum_pg_language_lancompiler 5
#define Anum_pg_language_lanacl 6
/* ----------------
* initial contents of pg_language
* ----------------
*/
DATA(insert OID = 12 ( internal f f 0 "n/a" ));
DATA(insert OID = 12 ( "internal" f f 0 "n/a" _null_ ));
DESCR("Built-in functions");
#define INTERNALlanguageId 12
DATA(insert OID = 13 ( "C" f f 0 "/bin/cc" ));
DATA(insert OID = 13 ( "c" f f 0 "/bin/cc" _null_ ));
DESCR("Dynamically-loaded C functions");
#define ClanguageId 13
DATA(insert OID = 14 ( "sql" f f 0 "postgres"));
DATA(insert OID = 14 ( "sql" f t 0 "postgres" _null_ ));
DESCR("SQL-language functions");
#define SQLlanguageId 14

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: miscadmin.h,v 1.98 2002/01/01 23:16:22 tgl Exp $
* $Id: miscadmin.h,v 1.99 2002/02/18 23:11:31 petere Exp $
*
* NOTES
* some of the information in this file should be moved to
@ -227,6 +227,7 @@ extern char *convertstr(unsigned char *buff, int len, int dest);
/* in utils/misc/superuser.c */
extern bool superuser(void); /* current user is superuser */
extern bool superuser_arg(Oid userid); /* given user is superuser */
extern bool is_dbadmin(Oid dbid); /* current user is owner of
* database */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.96 2001/11/05 17:46:34 momjian Exp $
* $Id: nodes.h,v 1.97 2002/02/18 23:11:41 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -222,6 +222,8 @@ typedef enum NodeTag
T_CaseWhen,
T_FkConstraint,
T_PrivGrantee,
T_FuncWithArgs,
T_PrivTarget,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.151 2001/11/05 17:46:34 momjian Exp $
* $Id: parsenodes.h,v 1.152 2002/02/18 23:11:41 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -145,8 +145,9 @@ typedef struct GrantStmt
{
NodeTag type;
bool is_grant; /* not revoke */
List *relnames;
char *privileges;
int objtype;
List *objects;
List *privileges;
List *grantees;
} GrantStmt;
@ -159,6 +160,23 @@ typedef struct PrivGrantee
} PrivGrantee;
typedef struct FuncWithArgs
{
NodeTag type;
char *funcname;
List *funcargs;
} FuncWithArgs;
/* This is only used internally in gram.y. */
typedef struct PrivTarget
{
NodeTag type;
int objtype;
List *objs;
} PrivTarget;
/* ----------------------
* Close Portal Statement
* ----------------------

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: keywords.h,v 1.12 2001/11/05 17:46:34 momjian Exp $
* $Id: keywords.h,v 1.13 2002/02/18 23:11:45 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,5 +21,6 @@ typedef struct ScanKeyword
} ScanKeyword;
extern ScanKeyword *ScanKeywordLookup(char *text);
extern const char *TokenString(int token);
#endif /* KEYWORDS_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: acl.h,v 1.39 2001/11/05 17:46:36 momjian Exp $
* $Id: acl.h,v 1.40 2002/02/18 23:11:45 petere Exp $
*
* NOTES
* For backward-compatibility purposes we have to allow there
@ -171,7 +171,7 @@ extern char *aclcheck_error_strings[];
/*
* routines used internally
*/
extern Acl *acldefault(const char *relname, AclId ownerid);
extern Acl *acldefault(AclId ownerid);
extern Acl *aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg);
/*
@ -208,4 +208,7 @@ extern bool pg_func_ownercheck(Oid userid, char *funcname,
extern bool pg_aggr_ownercheck(Oid userid, char *aggname,
Oid basetypeID);
extern int32 pg_proc_aclcheck(Oid proc_oid, Oid userid);
extern int32 pg_language_aclcheck(Oid lang_oid, Oid userid);
#endif /* ACL_H */

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: fcache.h,v 1.20 2001/11/05 17:46:36 momjian Exp $
* $Id: fcache.h,v 1.21 2002/02/18 23:11:46 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -41,6 +41,8 @@ typedef struct FunctionCache
*/
FmgrInfo func;
bool permission_ok;
/*
* setArgsValid is true when we are evaluating a set-valued function
* and we are in the middle of a call series; we want to pass the same

View File

@ -188,6 +188,49 @@ SELECT * FROM atestv3; -- ok
-----+-----+-------
(0 rows)
-- privileges on functions, languages
-- switch to superuser
\c -
REVOKE ALL PRIVILEGES ON LANGUAGE sql FROM PUBLIC;
GRANT USAGE ON LANGUAGE sql TO regressuser1; -- ok
GRANT USAGE ON LANGUAGE c TO PUBLIC; -- fail
ERROR: language "c" is not trusted
SET SESSION AUTHORIZATION regressuser1;
GRANT USAGE ON LANGUAGE sql TO regressuser2; -- fail
ERROR: permission denied
CREATE FUNCTION testfunc1(int) RETURNS int AS 'select 2 * $1;' LANGUAGE sql;
CREATE FUNCTION testfunc2(int) RETURNS int AS 'select 3 * $1;' LANGUAGE sql;
GRANT EXECUTE ON FUNCTION testfunc1(int), testfunc2(int) TO regressuser2;
GRANT USAGE ON FUNCTION testfunc1(int) TO regressuser3; -- semantic error
ERROR: invalid privilege type USAGE for function object
GRANT ALL PRIVILEGES ON FUNCTION testfunc1(int) TO regressuser4;
GRANT ALL PRIVILEGES ON FUNCTION testfunc_nosuch(int) TO regressuser4;
ERROR: Function 'testfunc_nosuch(int4)' does not exist
SET SESSION AUTHORIZATION regressuser2;
SELECT testfunc1(5), testfunc2(5); -- ok
testfunc1 | testfunc2
-----------+-----------
10 | 15
(1 row)
CREATE FUNCTION testfunc3(int) RETURNS int AS 'select 2 * $1;' LANGUAGE sql; -- fail
ERROR: permission denied
SET SESSION AUTHORIZATION regressuser3;
SELECT testfunc1(5); -- fail
ERROR: permission denied
SET SESSION AUTHORIZATION regressuser4;
SELECT testfunc1(5); -- ok
testfunc1
-----------
10
(1 row)
DROP FUNCTION testfunc1(int); -- fail
ERROR: RemoveFunction: function 'testfunc1': permission denied
\c -
DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity
GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
-- has_table_privilege function
-- bad-input checks
select has_table_privilege(NULL,'pg_shadow','select');
@ -207,7 +250,7 @@ ERROR: pg_aclcheck: invalid user id 4293967297
select has_table_privilege(1,'rule');
ERROR: has_table_privilege: invalid relation oid 1
-- superuser
\c regression
\c -
select has_table_privilege(current_user,'pg_shadow','select');
has_table_privilege
---------------------

View File

@ -126,6 +126,42 @@ SELECT * FROM atestv1; -- ok
SELECT * FROM atestv3; -- ok
-- privileges on functions, languages
-- switch to superuser
\c -
REVOKE ALL PRIVILEGES ON LANGUAGE sql FROM PUBLIC;
GRANT USAGE ON LANGUAGE sql TO regressuser1; -- ok
GRANT USAGE ON LANGUAGE c TO PUBLIC; -- fail
SET SESSION AUTHORIZATION regressuser1;
GRANT USAGE ON LANGUAGE sql TO regressuser2; -- fail
CREATE FUNCTION testfunc1(int) RETURNS int AS 'select 2 * $1;' LANGUAGE sql;
CREATE FUNCTION testfunc2(int) RETURNS int AS 'select 3 * $1;' LANGUAGE sql;
GRANT EXECUTE ON FUNCTION testfunc1(int), testfunc2(int) TO regressuser2;
GRANT USAGE ON FUNCTION testfunc1(int) TO regressuser3; -- semantic error
GRANT ALL PRIVILEGES ON FUNCTION testfunc1(int) TO regressuser4;
GRANT ALL PRIVILEGES ON FUNCTION testfunc_nosuch(int) TO regressuser4;
SET SESSION AUTHORIZATION regressuser2;
SELECT testfunc1(5), testfunc2(5); -- ok
CREATE FUNCTION testfunc3(int) RETURNS int AS 'select 2 * $1;' LANGUAGE sql; -- fail
SET SESSION AUTHORIZATION regressuser3;
SELECT testfunc1(5); -- fail
SET SESSION AUTHORIZATION regressuser4;
SELECT testfunc1(5); -- ok
DROP FUNCTION testfunc1(int); -- fail
\c -
DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity
GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
-- has_table_privilege function
-- bad-input checks
@ -137,7 +173,7 @@ select has_table_privilege(-999999,'pg_shadow','update');
select has_table_privilege(1,'rule');
-- superuser
\c regression
\c -
select has_table_privilege(current_user,'pg_shadow','select');
select has_table_privilege(current_user,'pg_shadow','insert');