Tom Lane <t...@sss.pgh.pa.us> Wednesday 23 February 2011 16:19:27
> rsmogura <rsmog...@softperience.eu> writes:
> >  On Tue, 22 Feb 2011 20:20:39 -0500, Tom Lane wrote:
> >> ...  But my question isn't about that; it's about
> >> why aclitem should be considered a first-class citizen.  It makes me
> >> uncomfortable that client apps are looking at it at all, because any
> >> that do are bound to get broken in the future, even assuming that
> >> they get the right answers today.  I wonder how many such clients are up
> >> to speed for per-column privileges and non-constant default privileges
> >> for instance.  And sepgsql is going to cut them off at the knees.
> >> 
> >  Technically, at eye glance, I didn't seen in sepgsql modifications to
> >  acl.h. So, I think, aclitem will be unaffected. In any way sepgsql needs
> >  some way to present access rights to administrator it may use own model,
> >  or aclitem, too.
> 
> You're missing the point, which is that the current internal
> representation of aclitem could change drastically to support future
> feature improvements in the area of privileges.  It has already changed
> significantly in the past (we didn't use to have WITH GRANT OPTION).
> If we had to add a field, for instance, a binary representation would
> simply be broken, as clients would have difficulty telling how to
> interpret it as soon as there was more than one possible format.
> Text representations are typically a bit more extensible.
> 
>                       regards, tom lane

Here is extended version, has version field (N_ACL_RIGHTS*2) and reserved 
mask, as well definition is more general then def of PGSQL. In any way it 
require that rights mades bit array.

Still I tested only aclitemsend.

Btw, Is it possible and needed to add group byte, indicating that grantee is 
group or user?

Regards,
Radek
diff --git a/.gitignore b/.gitignore
index 1be11e8..0d594f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ objfiles.txt
 /GNUmakefile
 /config.log
 /config.status
+/nbproject/private/
+/nbproject
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 691ba3b..c25c0fd 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -33,6 +33,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/syscache.h"
+#include "libpq/pqformat.h"
 
 
 typedef struct
@@ -78,6 +79,10 @@ static void putid(char *p, const char *s);
 static Acl *allocacl(int n);
 static void check_acl(const Acl *acl);
 static const char *aclparse(const char *s, AclItem *aip);
+
+/** Assigns default grantor and send warning. */
+static void aclitem_assign_default_grantor(AclItem *aip);
+
 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
 static int	aclitemComparator(const void *arg1, const void *arg2);
 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
@@ -209,6 +214,14 @@ putid(char *p, const char *s)
 	*p = '\0';
 }
 
+/** Assigns default grantor and send warning. */
+void aclitem_assign_default_grantor(AclItem *aip) {
+    aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
+    ereport(WARNING,
+                    (errcode(ERRCODE_INVALID_GRANTOR),
+                     errmsg("defaulting grantor to user ID %u",
+                                    BOOTSTRAP_SUPERUSERID)));
+}
 /*
  * aclparse
  *		Consumes and parses an ACL specification of the form:
@@ -343,11 +356,7 @@ aclparse(const char *s, AclItem *aip)
 	}
 	else
 	{
-		aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
-		ereport(WARNING,
-				(errcode(ERRCODE_INVALID_GRANTOR),
-				 errmsg("defaulting grantor to user ID %u",
-						BOOTSTRAP_SUPERUSERID)));
+            aclitem_assign_default_grantor(aip);
 	}
 
 	ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
@@ -643,6 +652,163 @@ aclitemout(PG_FUNCTION_ARGS)
 
 	PG_RETURN_CSTRING(out);
 }
+/** Do binary read of aclitem. Input format is same as {@link aclitem_recv}, but
+ * special algorithm is used to determine grantee's and grantor's OID. The reason
+ * is to keep backward "information" compatiblity with text mode - typical
+ * client (which gets instructions from user)
+ * may be much more interested in sending grantee and grantors name then
+ * OID. Detailed rule is as follow:<br/>
+ * If message has no name and names' length then
+ * use passed OIDs (message may be truncated, we accept this, 
+ * but both, two last fields must be not present).<br/>
+ * If grantee's name len or grantor's name len is {@code -1} then use respecitve
+ * OIDs.<br/>
+ * If name length is not {@code -1} then find OID for given part, and
+ * ensure that respective OID is {@code 0} or is equal to found OID.</br>
+ * If grantor's OID is {@code 0} and grantor's name lenght is {@code -1} or 
+ * truncated then assign superuser as grantor.
+ */
+Datum
+aclitemrecv(PG_FUNCTION_ARGS) {
+    StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+    AclItem    *aip;
+    int        gRawLen;
+    char       *gVal = NULL;
+    int4        gValLen;
+    Oid        gOid;
+    int2       numberOfAcls;
+    int4       mask;
+    
+    aip = (AclItem *) palloc(sizeof(AclItem));
+    aip->ai_grantee = pq_getmsgint(buf, 4);
+    aip->ai_grantor = pq_getmsgint(buf, 4);
+    numberOfAcls = pq_getmsgint(buf, 2);
+    if (numberOfAcls != N_ACL_RIGHTS * 2) {
+        ereport(ERROR,
+                    (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                    errmsg("grantee's OID is not 0 and passed grantee's name and grantee's OID doesn't match")));                
+        aip->ai_privs = ACL_NO_RIGHTS;
+        PG_RETURN_ACLITEM_P(aip);
+    }
+    
+    aip->ai_privs = pq_getmsgint(buf, 4);
+    mask = pq_getmsgint(buf, 4);
+    
+    /* Client has passed names. */
+    if (buf->cursor < buf->len) {
+        /* Read grantee. */
+        gRawLen = pq_getmsgint(buf, 4);
+        if (gRawLen != -1) {
+            gVal = pq_getmsgtext(buf, gRawLen, &gValLen);
+            gOid = get_role_oid(gVal, false);
+            if (aip->ai_grantee != 0 && aip->ai_grantee != gOid) {
+                ereport(ERROR,
+                            (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                            errmsg("grantee's OID is not 0 and passed grantee's name and grantee's OID doesn't match")));
+                
+            }
+        }
+        
+        /* Read grantor. */
+        gRawLen = pq_getmsgint(buf, 4);
+        if (gRawLen != -1) {
+            gVal = pq_getmsgtext(buf, gRawLen, &gValLen);
+            gOid = get_role_oid(gVal, false);
+            if (aip->ai_grantor != 0 && aip->ai_grantor != gOid) {
+                ereport(ERROR,
+                            (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                            errmsg("grantor's OID is not 0 and passed grantor's name and grantor's OID doesn't match")));
+            }
+        }else {
+            gVal = NULL;
+        }
+    }
+    
+    if (aip->ai_grantor == 0 && gVal == NULL)
+        aclitem_assign_default_grantor(aip);
+    
+    PG_RETURN_ACLITEM_P(aip);
+}
+/**
+ * The output format is as follows:
+ * <ol>
+ * <li>grantee's oid</li>
+ * <li>grantor's oid</li>
+ * <li>number of rights (describes priviliges set version) (short)</li>
+ * <li>rights - N-bit number</li>
+ * <li>mask (reserved for future usage) - N-bit number</li>
+ * <li>grentee's name length</li>
+ * <li>grantee's name</li>
+ * <li>grantor's name length</li>
+ * <li>grantor's name</li>
+ * </ol>
+ * "Number of rights" - describes how many rights PSQL has defined. Each right
+ * has internal number <i>n</i> and is represented by bit 1 set on <i>n</i>-th 
+ * internal positon. Currently we have 24 rigths (12 base and 12 grantor)<br/>
+ * N is lowest number such that {@code N%8 == 0 && N >= 32 && N >= "Number of rights"
+ * <br/>
+ * <b>Backend implementation notice</b>
+ * Currently, when I wrote this
+ * rights indexed from 1-12 represents "base" privilege, rights 16-29 represents
+ * privilige to grant base privilige. So, rights 13-15, 30-32 are reserved for 
+ * future usage.
+ * <br/>
+ * Magic lenght for grantee's or grantor's name -1 means that respecitive
+ * is unnamed, which will be, for example, for {@link ACL_ID_PUBLIC}.
+ * <br/>
+ * Last elements are used to pass "usefull" information to client, so it
+ * don't need to query for those names, actually client may be more
+ * interested in getting those names, then OIDs. It will keep backward
+ * compatibility with text mode, as well.
+ */
+Datum
+aclitemsend(PG_FUNCTION_ARGS)
+{
+	AclItem    *aip = PG_GETARG_ACLITEM_P(0);
+	char	   *oidName;
+	HeapTuple	htup;
+        StringInfoData  buf;
+        //Here we use simplification of documentation, because of we have < 16 priviliges
+        pq_begintypsend(&buf);        
+        pq_sendint(&buf, aip->ai_grantee, 4);
+        pq_sendint(&buf, aip->ai_grantor, 4);
+        //Version
+        pq_sendint(&buf, N_ACL_RIGHTS*2, 2); 
+        pq_sendint(&buf, aip->ai_privs, 4);
+        //Mask currently all 1
+        pq_sendint(&buf, 0xFFffFFff, 4); 
+        if (N_ACL_RIGHTS > 16) {
+            /* We sends rights as long (16 bit), but if in future number
+             * of rights will increase we got problem.
+             */
+        }
+        
+        /** Append names at the end. */
+	if (aip->ai_grantee != ACL_ID_PUBLIC) {
+		htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
+		if (HeapTupleIsValid(htup)) {
+			oidName = NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname);
+                        pq_sendcountedtext(&buf, oidName, strlen(oidName), false);
+			ReleaseSysCache(htup);
+		}else {
+                    pq_sendint(&buf,-1, 4);
+		}
+	}else {
+            pq_sendint(&buf, -1, 4);
+        }
+
+	htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
+	if (HeapTupleIsValid(htup)) {
+            oidName = NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname);
+            pq_sendcountedtext(&buf, oidName, strlen(oidName), false);
+            ReleaseSysCache(htup);
+	}
+	else {
+            pq_sendint(&buf, -1, 4);
+	}
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
 
 /*
  * aclitem_match
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 8c940bb..c56d8f8 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4230,6 +4230,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 22
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 17 "2278" _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3122 (  aclitemrecv			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 1033 "2281" _null_ _null_ _null_ _null_ aclitemrecv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3123 (  aclitemsend			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 17 "1033" _null_ _null_ _null_ _null_	aclitemsend _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_	pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 9baed6c..f89ed44 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -462,7 +462,7 @@ DATA(insert OID = 1023 (  _abstime	 PGNSP PGUID -1 f b A f t \054 0 702 0 array_
 DATA(insert OID = 1024 (  _reltime	 PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
 DATA(insert OID = 1025 (  _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
 DATA(insert OID = 1027 (  _polygon	 PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout aclitemrecv aclitemsend - - - i p f 0 -1 0 0 _null_ _null_ ));
 DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 1e9cf7f..1ca959d 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -239,6 +239,8 @@ extern void initialize_acl(void);
  */
 extern Datum aclitemin(PG_FUNCTION_ARGS);
 extern Datum aclitemout(PG_FUNCTION_ARGS);
+extern Datum aclitemrecv(PG_FUNCTION_ARGS);
+extern Datum aclitemsend(PG_FUNCTION_ARGS);
 extern Datum aclinsert(PG_FUNCTION_ARGS);
 extern Datum aclremove(PG_FUNCTION_ARGS);
 extern Datum aclcontains(PG_FUNCTION_ARGS);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to