Re: Patch for %Allow per-database permissions to be set via - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Patch for %Allow per-database permissions to be set via
Date
Msg-id 200604300209.k3U29cm17114@candle.pha.pa.us
Whole thread Raw
In response to Patch for %Allow per-database permissions to be set via GRANT  (Gevik Babakhani <pgdev@xs4all.nl>)
Responses Re: Patch for %Allow per-database permissions to be set via  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
Documentation added, patch attached and applied.  Thanks.

---------------------------------------------------------------------------

Gevik Babakhani wrote:
> This patch implements the TODO Item: "%Allow per-database permissions to
> be set via GRANT"
>
> Implementation details:
>
> 1. A privilege ACL_CONNECT has been added to the ACL bits
>
> 2. The ACL_CONNECT can be recognized by character "c" in
> pg_database/dataacl
>
> 3. The patch implements:
>
> GRANT CONNECTION ON DATABASE mydatabase TO myuser
>
> REVOKE CONNECTION ON DATABASE mydatabase FROM myuser
>
> 4. The initial condition ACL=NULL is treated as default
> ACL=ACL_CREATE_TEMP | ACL_CONNECT providing backward compatibility with
> the current pg_hba.conf
> Notes:
>
> As discussed :
> A database owner WITHOUT SUPERUSER privileges can lock himself out from
> connecting to his database. Try:
>
> #psql -U user1 -d user1
> Revoke connection on database user1 from public;
> Revoke connection on database user1 from user1;
>
> In this case no warning will be shown to the user informing he/she is
> possibly locked out. This behavior is discussed in the hackers list.
>
> The solution for a possible lockout would be to connect as a superuser
> and GRANT CONNECTION ON DATABASE user1 TO <anyuser or public>
>
> The implementation is best used for systems not wishing to change
> pg_hba.conf frequently. In that case a simple host record can be added
> to pg_hba.conf, providing from witch network the server is allowed to be
> connected from and the database connection privilege can be granted or
> revoked from withing SQL.
>
> e.g.
> CREATE USER user1 LOGIN;
> CREATE USER user2 LOGIN;
> CREATE DATABASE user1 OWNER user1;
> REVOKE CONNECTION ON DATABASE user1 FROM PUBLIC;
> GRANT CONNECTION,CREATE ON DATABASE user1 TO user2;
> SELECT datname,datacl FROM pg_catalog.pg_database;
>
> The patch can be downloaded from:
>
> http://www.xs4all.nl/~gevik/patch/patch-0.7.diff
>
> Many thanks to Tom Lane and Alvaro Herrera for their insight and
> coaching.
>
> Regards,
> Gevik.
>
>
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: if posting/reading through Usenet, please send an appropriate
>        subscribe-nomail command to majordomo@postgresql.org so that your
>        message can get through to the mailing list cleanly
>

--
  Bruce Momjian   http://candle.pha.pa.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +
Index: doc/src/sgml/client-auth.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v
retrieving revision 1.87
diff -c -c -r1.87 client-auth.sgml
*** doc/src/sgml/client-auth.sgml    10 Mar 2006 19:10:47 -0000    1.87
--- doc/src/sgml/client-auth.sgml    30 Apr 2006 01:42:16 -0000
***************
*** 206,211 ****
--- 206,213 ----
         Multiple user names can be supplied by separating them with commas.
         A separate file containing user names can be specified by preceding the
         file name with <literal>@</>.
+        User and group connectivity can also be restricted by <command>GRANT
+        CONNECTION ON DATABASE</>.
        </para>
       </listitem>
      </varlistentry>
Index: doc/src/sgml/ref/grant.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v
retrieving revision 1.52
diff -c -c -r1.52 grant.sgml
*** doc/src/sgml/ref/grant.sgml    14 Feb 2006 03:32:14 -0000    1.52
--- doc/src/sgml/ref/grant.sgml    30 Apr 2006 01:42:16 -0000
***************
*** 30,36 ****
      ON SEQUENCE <replaceable class="PARAMETER">sequencename</replaceable> [, ...]
      TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 

! GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
      ON DATABASE <replaceable>dbname</replaceable> [, ...]
      TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 

--- 30,36 ----
      ON SEQUENCE <replaceable class="PARAMETER">sequencename</replaceable> [, ...]
      TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 

! GRANT { { CREATE | TEMPORARY | TEMP | CONNECTION } [,...] | ALL [ PRIVILEGES ] }
      ON DATABASE <replaceable>dbname</replaceable> [, ...]
      TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 

***************
*** 230,235 ****
--- 230,247 ----
      </varlistentry>

      <varlistentry>
+      <term>CONNECTION</term>
+      <listitem>
+       <para>
+        Allows the ability to connect to the specified database.
+        By default, Grant permissions allow users to connect to any database,
+        though <filename>pg_hba.conf</> can add additional connection
+        restrictions.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term>TEMPORARY</term>
       <term>TEMP</term>
       <listitem>
***************
*** 417,422 ****
--- 429,435 ----
                    X -- EXECUTE
                    U -- USAGE
                    C -- CREATE
+                   c -- CONNECTION
                    T -- TEMPORARY
              arwdRxt -- ALL PRIVILEGES (for tables)
                    * -- grant option for preceding privilege
Index: doc/src/sgml/ref/revoke.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v
retrieving revision 1.36
diff -c -c -r1.36 revoke.sgml
*** doc/src/sgml/ref/revoke.sgml    21 Jan 2006 02:16:18 -0000    1.36
--- doc/src/sgml/ref/revoke.sgml    30 Apr 2006 01:42:16 -0000
***************
*** 35,41 ****
      [ CASCADE | RESTRICT ]

  REVOKE [ GRANT OPTION FOR ]
!     { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
      ON DATABASE <replaceable>dbname</replaceable> [, ...]
      FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] 
      [ CASCADE | RESTRICT ]
--- 35,41 ----
      [ CASCADE | RESTRICT ]

  REVOKE [ GRANT OPTION FOR ]
!     { { CREATE | TEMPORARY | TEMP | CONNECTION } [,...] | ALL [ PRIVILEGES ] }
      ON DATABASE <replaceable>dbname</replaceable> [, ...]
      FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] 
      [ CASCADE | RESTRICT ]
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.125
diff -c -c -r1.125 aclchk.c
*** src/backend/catalog/aclchk.c    5 Mar 2006 15:58:22 -0000    1.125
--- src/backend/catalog/aclchk.c    30 Apr 2006 01:42:17 -0000
***************
*** 1368,1373 ****
--- 1368,1375 ----
          return ACL_CREATE_TEMP;
      if (strcmp(privname, "temp") == 0)
          return ACL_CREATE_TEMP;
+     if (strcmp(privname, "connection") == 0)
+         return ACL_CONNECT;
      ereport(ERROR,
              (errcode(ERRCODE_SYNTAX_ERROR),
               errmsg("unrecognized privilege type \"%s\"", privname)));
***************
*** 1401,1406 ****
--- 1403,1410 ----
              return "CREATE";
          case ACL_CREATE_TEMP:
              return "TEMP";
+         case ACL_CONNECT:
+             return "CONNECTION";
          default:
              elog(ERROR, "unrecognized privilege: %d", (int) privilege);
      }
Index: src/backend/utils/adt/acl.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v
retrieving revision 1.131
diff -c -c -r1.131 acl.c
*** src/backend/utils/adt/acl.c    5 Mar 2006 15:58:40 -0000    1.131
--- src/backend/utils/adt/acl.c    30 Apr 2006 01:42:18 -0000
***************
*** 287,292 ****
--- 287,295 ----
              case ACL_CREATE_TEMP_CHR:
                  read = ACL_CREATE_TEMP;
                  break;
+             case ACL_CONNECT_CHR:
+                 read = ACL_CONNECT;
+                 break;
              default:
                  ereport(ERROR,
                          (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
***************
*** 550,556 ****
              owner_default = ACL_ALL_RIGHTS_SEQUENCE;
              break;
          case ACL_OBJECT_DATABASE:
!             world_default = ACL_CREATE_TEMP;    /* not NO_RIGHTS! */
              owner_default = ACL_ALL_RIGHTS_DATABASE;
              break;
          case ACL_OBJECT_FUNCTION:
--- 553,559 ----
              owner_default = ACL_ALL_RIGHTS_SEQUENCE;
              break;
          case ACL_OBJECT_DATABASE:
!             world_default = ACL_CREATE_TEMP | ACL_CONNECT;    /* not NO_RIGHTS! */
              owner_default = ACL_ALL_RIGHTS_DATABASE;
              break;
          case ACL_OBJECT_FUNCTION:
Index: src/backend/utils/init/postinit.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.162
diff -c -c -r1.162 postinit.c
*** src/backend/utils/init/postinit.c    29 Mar 2006 21:17:39 -0000    1.162
--- src/backend/utils/init/postinit.c    30 Apr 2006 01:42:19 -0000
***************
*** 51,57 ****


  static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
! static void ReverifyMyDatabase(const char *name);
  static void InitCommunication(void);
  static void ShutdownPostgres(int code, Datum arg);
  static bool ThereIsAtLeastOneRole(void);
--- 51,57 ----


  static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
! static void ReverifyMyDatabase(const char *name, const char *user_name);
  static void InitCommunication(void);
  static void ShutdownPostgres(int code, Datum arg);
  static bool ThereIsAtLeastOneRole(void);
***************
*** 130,137 ****
   * during session startup, this place is also fitting to set up any
   * database-specific configuration variables.
   */
  static void
! ReverifyMyDatabase(const char *name)
  {
      Relation    pgdbrel;
      SysScanDesc pgdbscan;
--- 130,138 ----
   * during session startup, this place is also fitting to set up any
   * database-specific configuration variables.
   */
+
  static void
! ReverifyMyDatabase(const char *name, const char *user_name)
  {
      Relation    pgdbrel;
      SysScanDesc pgdbscan;
***************
*** 211,216 ****
--- 212,234 ----
                      (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                       errmsg("too many connections for database \"%s\"",
                              name)));
+
+         /*
+          * Checking for privilege to connect to the database
+          * We want to bypass the test if we are running in bootstrap mode
+          */
+         if (!IsBootstrapProcessingMode())
+         {
+                 if(pg_database_aclcheck(MyDatabaseId,GetUserId()
+                     ,ACL_CONNECT) != ACLCHECK_OK )
+                 {
+                     ereport(FATAL,
+                             (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                  errmsg("couldn't connect to database %s", NameStr(dbform->datname)),
+                                  errdetail("User %s doesn't have the CONNECTION privilege for database %s.",
+                                 user_name, NameStr(dbform->datname))));
+                 }
+         }
      }

      /*
***************
*** 487,493 ****
       * superuser, so the above stuff has to happen first.)
       */
      if (!bootstrap)
!         ReverifyMyDatabase(dbname);

      /*
       * Final phase of relation cache startup: write a new cache file if
--- 505,511 ----
       * superuser, so the above stuff has to happen first.)
       */
      if (!bootstrap)
!         ReverifyMyDatabase(dbname,username);

      /*
       * Final phase of relation cache startup: write a new cache file if
Index: src/include/catalog/catversion.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/catversion.h,v
retrieving revision 1.326
diff -c -c -r1.326 catversion.h
*** src/include/catalog/catversion.h    26 Apr 2006 22:33:13 -0000    1.326
--- src/include/catalog/catversion.h    30 Apr 2006 01:42:19 -0000
***************
*** 53,58 ****
   */

  /*                            yyyymmddN */
! #define CATALOG_VERSION_NO    200604262

  #endif
--- 53,58 ----
   */

  /*                            yyyymmddN */
! #define CATALOG_VERSION_NO    200604291

  #endif
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.308
diff -c -c -r1.308 parsenodes.h
*** src/include/nodes/parsenodes.h    27 Apr 2006 00:33:46 -0000    1.308
--- src/include/nodes/parsenodes.h    30 Apr 2006 01:42:20 -0000
***************
*** 57,63 ****
  #define ACL_USAGE        (1<<8)    /* for languages and namespaces */
  #define ACL_CREATE        (1<<9)    /* for namespaces and databases */
  #define ACL_CREATE_TEMP (1<<10) /* for databases */
! #define N_ACL_RIGHTS    11        /* 1 plus the last 1<<x */
  #define ACL_NO_RIGHTS    0
  /* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
  #define ACL_SELECT_FOR_UPDATE    ACL_UPDATE
--- 57,64 ----
  #define ACL_USAGE        (1<<8)    /* for languages and namespaces */
  #define ACL_CREATE        (1<<9)    /* for namespaces and databases */
  #define ACL_CREATE_TEMP (1<<10) /* for databases */
! #define ACL_CONNECT    (1<<11) /* for database connection privilege */
! #define N_ACL_RIGHTS    12        /* 1 plus the last 1<<x */
  #define ACL_NO_RIGHTS    0
  /* Currently, SELECT ... FOR UPDATE/FOR SHARE requires UPDATE privileges */
  #define ACL_SELECT_FOR_UPDATE    ACL_UPDATE
Index: src/include/utils/acl.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/acl.h,v
retrieving revision 1.93
diff -c -c -r1.93 acl.h
*** src/include/utils/acl.h    5 Mar 2006 15:59:06 -0000    1.93
--- src/include/utils/acl.h    30 Apr 2006 01:42:20 -0000
***************
*** 135,150 ****
  #define ACL_USAGE_CHR            'U'
  #define ACL_CREATE_CHR            'C'
  #define ACL_CREATE_TEMP_CHR        'T'

  /* string holding all privilege code chars, in order by bitmask position */
! #define ACL_ALL_RIGHTS_STR    "arwdRxtXUCT"

  /*
   * Bitmasks defining "all rights" for each supported object type
   */
  #define ACL_ALL_RIGHTS_RELATION
(ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
  #define ACL_ALL_RIGHTS_SEQUENCE        (ACL_USAGE|ACL_SELECT|ACL_UPDATE)
! #define ACL_ALL_RIGHTS_DATABASE        (ACL_CREATE|ACL_CREATE_TEMP)
  #define ACL_ALL_RIGHTS_FUNCTION        (ACL_EXECUTE)
  #define ACL_ALL_RIGHTS_LANGUAGE        (ACL_USAGE)
  #define ACL_ALL_RIGHTS_NAMESPACE    (ACL_USAGE|ACL_CREATE)
--- 135,151 ----
  #define ACL_USAGE_CHR            'U'
  #define ACL_CREATE_CHR            'C'
  #define ACL_CREATE_TEMP_CHR        'T'
+ #define ACL_CONNECT_CHR            'c'

  /* string holding all privilege code chars, in order by bitmask position */
! #define ACL_ALL_RIGHTS_STR    "arwdRxtXUCTc"

  /*
   * Bitmasks defining "all rights" for each supported object type
   */
  #define ACL_ALL_RIGHTS_RELATION
(ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
  #define ACL_ALL_RIGHTS_SEQUENCE        (ACL_USAGE|ACL_SELECT|ACL_UPDATE)
! #define ACL_ALL_RIGHTS_DATABASE        (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT )
  #define ACL_ALL_RIGHTS_FUNCTION        (ACL_EXECUTE)
  #define ACL_ALL_RIGHTS_LANGUAGE        (ACL_USAGE)
  #define ACL_ALL_RIGHTS_NAMESPACE    (ACL_USAGE|ACL_CREATE)

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Patch for BUG #2073: Can't drop sequence when created
Next
From: Tom Lane
Date:
Subject: Re: pgstat: delayed write of stats file