OSDN Git Service

Represent grant options in the information schema.
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 11 Jun 2003 09:23:55 +0000 (09:23 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 11 Jun 2003 09:23:55 +0000 (09:23 +0000)
src/backend/catalog/information_schema.sql
src/backend/utils/adt/acl.c
src/include/catalog/pg_proc.h
src/include/utils/acl.h

index c1ca85c..224e61f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright 2002, PostgreSQL Global Development Group
  *
- * $Id: information_schema.sql,v 1.7 2003/06/05 16:08:47 petere Exp $
+ * $Id: information_schema.sql,v 1.8 2003/06/11 09:23:55 petere Exp $
  */
 
 
@@ -604,7 +604,7 @@ GRANT SELECT ON referential_constraints TO PUBLIC;
  */
 
 CREATE VIEW routine_privileges AS
-    SELECT CAST(u_owner.usename AS sql_identifier) AS grantor,
+    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
            CAST(u_grantee.usename AS sql_identifier) AS grantee,
            CAST(current_database() AS sql_identifier) AS specific_catalog,
            CAST(n.nspname AS sql_identifier) AS specific_schema,
@@ -613,17 +613,22 @@ CREATE VIEW routine_privileges AS
            CAST(n.nspname AS sql_identifier) AS routine_schema,
            CAST(p.proname AS sql_identifier) AS routine_name,
            CAST('EXECUTE' AS character_data) AS privilege_type,
-           CAST('NO' AS character_data) AS is_grantable
+           CAST(
+             CASE WHEN aclcontains(p.proacl,
+                                   makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', true))
+                  THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
-    FROM pg_user u_owner,
-         pg_user u_grantee,
+    FROM pg_proc p,
          pg_namespace n,
-         pg_proc p
+         pg_user u_grantor,
+         (SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee
 
-    WHERE u_owner.usesysid = p.proowner
-          AND p.pronamespace = n.oid
-          AND has_function_privilege(u_grantee.usename, p.oid, 'EXECUTE')
-          AND (u_owner.usename = current_user OR u_grantee.usename = current_user);
+    WHERE p.pronamespace = n.oid
+          AND aclcontains(p.proacl,
+                          makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', false))
+          AND (u_grantor.usename = current_user
+               OR u_grantee.usename = current_user
+               OR u_grantee.usename = 'PUBLIC');
 
 GRANT SELECT ON routine_privileges TO PUBLIC;
 
@@ -940,27 +945,31 @@ GRANT SELECT ON table_constraints TO PUBLIC;
  */
 
 CREATE VIEW table_privileges AS
-    SELECT CAST(u_owner.usename AS sql_identifier) AS grantor,
+    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
            CAST(u_grantee.usename AS sql_identifier) AS grantee,
            CAST(current_database() AS sql_identifier) AS table_catalog,
            CAST(nc.nspname AS sql_identifier) AS table_schema,
            CAST(c.relname AS sql_identifier) AS table_name,
            CAST(pr.type AS character_data) AS privilege_type,
-           CAST('NO' AS character_data) AS is_grantable,
+           CAST(
+             CASE WHEN aclcontains(c.relacl,
+                                   makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, true))
+                  THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
            CAST('NO' AS character_data) AS with_hierarchy
 
-    FROM pg_user u_owner,
-         pg_user u_grantee,
+    FROM pg_class c,
          pg_namespace nc,
-         pg_class c,
+         pg_user u_grantor,
+         (SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee,
          (SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE'
           UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type)
 
-    WHERE u_owner.usesysid = c.relowner
-          AND c.relnamespace = nc.oid
-          AND has_table_privilege(u_grantee.usename, c.oid, pr.type)
-
-          AND (u_owner.usename = current_user OR u_grantee.usename = current_user);
+    WHERE c.relnamespace = nc.oid
+          AND aclcontains(c.relacl,
+                          makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, false))
+          AND (u_grantor.usename = current_user
+               OR u_grantee.usename = current_user
+               OR u_grantee.usename = 'PUBLIC');
 
 GRANT SELECT ON table_privileges TO PUBLIC;
 
index 84abec0..2870b5d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.87 2003/06/02 19:00:29 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.88 2003/06/11 09:23:55 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 static const char *getid(const char *s, char *n);
 static void putid(char *p, const char *s);
-static Acl *makeacl(int n);
+static Acl *allocacl(int n);
 static const char *aclparse(const char *s, AclItem *aip);
 static bool aclitemeq(const AclItem *a1, const AclItem *a2);
 static Acl *recursive_revoke(Acl *acl, AclId grantee,
                                                         AclMode revoke_privs, DropBehavior behavior);
 
+static AclMode convert_priv_string(text *priv_type_text);
+
 static Oid     convert_table_name(text *tablename);
 static AclMode convert_table_priv_string(text *priv_type_text);
 static Oid     convert_database_name(text *databasename);
@@ -265,20 +267,20 @@ aclparse(const char *s, AclItem *aip)
 }
 
 /*
- * makeacl
+ * allocacl
  *             Allocates storage for a new Acl with 'n' entries.
  *
  * RETURNS:
  *             the new Acl
  */
 static Acl *
-makeacl(int n)
+allocacl(int n)
 {
        Acl                *new_acl;
        Size            size;
 
        if (n < 0)
-               elog(ERROR, "makeacl: invalid size: %d", n);
+               elog(ERROR, "allocacl: invalid size: %d", n);
        size = ACL_N_SIZE(n);
        new_acl = (Acl *) palloc0(size);
        new_acl->size = size;
@@ -471,7 +473,7 @@ acldefault(GrantObjectType objtype, AclId ownerid)
                        break;
        }
 
-       acl = makeacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
+       acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
                                  + (ownerid ? 1 : 0));
        aip = ACL_DAT(acl);
 
@@ -513,10 +515,10 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
 
        /* These checks for null input are probably dead code, but... */
        if (!old_acl || ACL_NUM(old_acl) < 1)
-               old_acl = makeacl(1);
+               old_acl = allocacl(1);
        if (!mod_aip)
        {
-               new_acl = makeacl(ACL_NUM(old_acl));
+               new_acl = allocacl(ACL_NUM(old_acl));
                memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
                return new_acl;
        }
@@ -536,7 +538,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
                if (aclitemeq(mod_aip, old_aip + dst))
                {
                        /* found a match, so modify existing item */
-                       new_acl = makeacl(num);
+                       new_acl = allocacl(num);
                        new_aip = ACL_DAT(new_acl);
                        memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
                        break;
@@ -546,7 +548,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
        if (dst == num)
        {
                /* need to append a new item */
-               new_acl = makeacl(num + 1);
+               new_acl = allocacl(num + 1);
                new_aip = ACL_DAT(new_acl);
                memcpy(new_aip, old_aip, num * sizeof(AclItem));
 
@@ -671,10 +673,10 @@ aclremove(PG_FUNCTION_ARGS)
 
        /* These checks for null input should be dead code, but... */
        if (!old_acl || ACL_NUM(old_acl) < 1)
-               old_acl = makeacl(1);
+               old_acl = allocacl(1);
        if (!mod_aip)
        {
-               new_acl = makeacl(ACL_NUM(old_acl));
+               new_acl = allocacl(ACL_NUM(old_acl));
                memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
                PG_RETURN_ACL_P(new_acl);
        }
@@ -689,13 +691,13 @@ aclremove(PG_FUNCTION_ARGS)
        if (dst >= old_num)
        {
                /* Not found, so return copy of source ACL */
-               new_acl = makeacl(old_num);
+               new_acl = allocacl(old_num);
                memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
        }
        else
        {
                new_num = old_num - 1;
-               new_acl = makeacl(new_num);
+               new_acl = allocacl(new_num);
                new_aip = ACL_DAT(new_acl);
                if (dst == 0)
                {                                               /* start */
@@ -734,13 +736,97 @@ aclcontains(PG_FUNCTION_ARGS)
        aidat = ACL_DAT(acl);
        for (i = 0; i < num; ++i)
        {
-               if (aip->ai_grantee == aidat[i].ai_grantee &&
-                       aip->ai_privs == aidat[i].ai_privs)
+               if (aip->ai_grantee == aidat[i].ai_grantee
+                       && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
+                       && aip->ai_grantor == aidat[i].ai_grantor
+                       && (ACLITEM_GET_PRIVS(*aip) & ACLITEM_GET_PRIVS(aidat[i])) == ACLITEM_GET_PRIVS(*aip)
+                       && (ACLITEM_GET_GOPTIONS(*aip) & ACLITEM_GET_GOPTIONS(aidat[i])) == ACLITEM_GET_GOPTIONS(*aip))
                        PG_RETURN_BOOL(true);
        }
        PG_RETURN_BOOL(false);
 }
 
+Datum
+makeaclitem(PG_FUNCTION_ARGS)
+{
+       int32           u_grantee = PG_GETARG_INT32(0);
+       int32           g_grantee = PG_GETARG_INT32(1);
+       int32           grantor = PG_GETARG_INT32(2);
+       text       *privtext = PG_GETARG_TEXT_P(3);
+       bool            goption = PG_GETARG_BOOL(4);
+       AclItem    *aclitem;
+       AclMode         priv;
+
+       priv = convert_priv_string(privtext);
+
+       aclitem = (AclItem *) palloc(sizeof(*aclitem));
+       if (u_grantee == 0 && g_grantee == 0)
+       {
+               aclitem->ai_grantee = 0;
+               ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
+       }
+       else if (u_grantee != 0 && g_grantee != 0)
+       {
+               elog(ERROR, "cannot specify both user and group");
+       }
+       else if (u_grantee != 0)
+       {
+               aclitem->ai_grantee = u_grantee;
+               ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
+       }
+       else if (g_grantee != 0)
+       {
+               aclitem->ai_grantee = g_grantee;
+               ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
+       }
+
+       aclitem->ai_grantor = grantor;
+       ACLITEM_SET_PRIVS(*aclitem, priv);
+       if (goption)
+               ACLITEM_SET_GOPTIONS(*aclitem, priv);
+       else
+               ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
+
+       PG_RETURN_ACLITEM_P(aclitem);
+}
+
+static AclMode
+convert_priv_string(text *priv_type_text)
+{
+       char       *priv_type;
+
+       priv_type = DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                       PointerGetDatum(priv_type_text)));
+
+       if (strcasecmp(priv_type, "SELECT") == 0)
+               return ACL_SELECT;
+       if (strcasecmp(priv_type, "INSERT") == 0)
+               return ACL_INSERT;
+       if (strcasecmp(priv_type, "UPDATE") == 0)
+               return ACL_UPDATE;
+       if (strcasecmp(priv_type, "DELETE") == 0)
+               return ACL_DELETE;
+       if (strcasecmp(priv_type, "RULE") == 0)
+               return ACL_RULE;
+       if (strcasecmp(priv_type, "REFERENCES") == 0)
+               return ACL_REFERENCES;
+       if (strcasecmp(priv_type, "TRIGGER") == 0)
+               return ACL_TRIGGER;
+       if (strcasecmp(priv_type, "EXECUTE") == 0)
+               return ACL_EXECUTE;
+       if (strcasecmp(priv_type, "USAGE") == 0)
+               return ACL_USAGE;
+       if (strcasecmp(priv_type, "CREATE") == 0)
+               return ACL_CREATE;
+       if (strcasecmp(priv_type, "TEMP") == 0)
+               return ACL_CREATE_TEMP;
+       if (strcasecmp(priv_type, "TEMPORARY") == 0)
+               return ACL_CREATE_TEMP;
+
+       elog(ERROR, "invalid privilege type %s", priv_type);
+       return ACL_NO_RIGHTS;           /* keep compiler quiet */
+}
+
 
 /*
  * has_table_privilege variants
index 7d6ff86..d8ce41c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.302 2003/05/26 00:11:27 tgl Exp $
+ * $Id: pg_proc.h,v 1.303 2003/06/11 09:23:55 petere Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -1318,6 +1318,8 @@ DATA(insert OID = 1036 (  aclremove                  PGNSP PGUID 12 f f t f s 2 1034 "1034 10
 DESCR("remove ACL item");
 DATA(insert OID = 1037 (  aclcontains     PGNSP PGUID 12 f f t f s 2 16 "1034 1033"    aclcontains - _null_ ));
 DESCR("does ACL contain item?");
+DATA(insert OID = 1365 (  makeaclitem     PGNSP PGUID 12 f f t f s 5 1033 "23 23 23 25 16"     makeaclitem - _null_ ));
+DESCR("make ACL item");
 DATA(insert OID = 1038 (  seteval                 PGNSP PGUID 12 f f t t v 1 23 "26"  seteval - _null_ ));
 DESCR("internal function supporting PostQuel-style sets");
 DATA(insert OID = 1044 (  bpcharin                PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" bpcharin - _null_ ));
index 871ed68..1a54042 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: acl.h,v 1.51 2003/01/23 23:39:07 petere Exp $
+ * $Id: acl.h,v 1.52 2003/06/11 09:23:55 petere Exp $
  *
  * NOTES
  *       For backward-compatibility purposes we have to allow there
@@ -70,6 +70,9 @@ typedef struct AclItem
   ((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ((privs) & 0x7FFF))
 #define ACLITEM_SET_GOPTIONS(item,goptions) \
   ((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (((goptions) & 0x7FFF) << 15) | ACLITEM_GET_PRIVS(item))
+#define ACLITEM_SET_IDTYPE(item,idtype) \
+  ((item).ai_privs = ((idtype)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ACLITEM_GET_PRIVS(item))
+
 #define ACLITEM_SET_PRIVS_IDTYPE(item,privs,goption,idtype) \
   ((item).ai_privs = ((privs) & 0x7FFF) |(((goption) & 0x7FFF) << 15) | ((idtype) << 30))
 
@@ -188,6 +191,7 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
 extern Datum aclinsert(PG_FUNCTION_ARGS);
 extern Datum aclremove(PG_FUNCTION_ARGS);
 extern Datum aclcontains(PG_FUNCTION_ARGS);
+extern Datum makeaclitem(PG_FUNCTION_ARGS);
 
 /*
  * prototypes for functions in aclchk.c