OSDN Git Service

Prevent ALTER USER f RESET ALL from removing the settings that were put there
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Mar 2010 14:44:34 +0000 (14:44 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Mar 2010 14:44:34 +0000 (14:44 +0000)
by a superuser -- "ALTER USER f RESET setting" already disallows removing such a
setting.

Apply the same treatment to ALTER DATABASE d RESET ALL when run by a database
owner that's not superuser.

doc/src/sgml/catalogs.sgml
src/backend/catalog/pg_db_role_setting.c
src/backend/utils/misc/guc.c
src/include/utils/guc.h

index 197b782..b104e0e 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.223 2010/02/17 04:19:37 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.224 2010/03/25 14:44:33 alvherre Exp $ -->
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
  -->
       <entry>Password expiry time (only used for password authentication);
        NULL if no expiration</entry>
      </row>
-
-     <row>
-      <entry><structfield>rolconfig</structfield></entry>
-      <entry><type>text[]</type></entry>
-      <entry>Session defaults for run-time configuration variables</entry>
-     </row>
     </tbody>
    </tgroup>
   </table>
index 6687cbf..a545095 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *             $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.3 2010/02/26 02:00:37 momjian Exp $
+ *             $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.4 2010/03/25 14:44:33 alvherre Exp $
  */
 #include "postgres.h"
 
@@ -49,7 +49,8 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
        /*
         * There are three cases:
         *
-        * - in RESET ALL, simply delete the pg_db_role_setting tuple (if any)
+        * - in RESET ALL, request GUC to reset the settings array and update the
+        * catalog if there's anything left, delete it otherwise
         *
         * - in other commands, if there's a tuple in pg_db_role_setting, update
         * it; if it ends up empty, delete it
@@ -60,7 +61,41 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
        if (setstmt->kind == VAR_RESET_ALL)
        {
                if (HeapTupleIsValid(tuple))
-                       simple_heap_delete(rel, &tuple->t_self);
+               {
+                       ArrayType  *new = NULL;
+                       Datum           datum;
+                       bool            isnull;
+
+                       datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
+                                                                RelationGetDescr(rel), &isnull);
+
+                       if (!isnull)
+                               new = GUCArrayReset(DatumGetArrayTypeP(datum));
+
+                       if (new)
+                       {
+                               Datum           repl_val[Natts_pg_db_role_setting];
+                               bool            repl_null[Natts_pg_db_role_setting];
+                               bool            repl_repl[Natts_pg_db_role_setting];
+                               HeapTuple       newtuple;
+
+                               memset(repl_repl, false, sizeof(repl_repl));
+
+                               repl_val[Anum_pg_db_role_setting_setconfig - 1] =
+                                       PointerGetDatum(new);
+                               repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
+                               repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
+
+                               newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
+                                                                                        repl_val, repl_null, repl_repl);
+                               simple_heap_update(rel, &tuple->t_self, newtuple);
+
+                               /* Update indexes */
+                               CatalogUpdateIndexes(rel, newtuple);
+                       }
+                       else
+                               simple_heap_delete(rel, &tuple->t_self);
+               }
        }
        else if (HeapTupleIsValid(tuple))
        {
index 30e90cb..ea43b41 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.544 2010/03/21 00:17:59 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.545 2010/03/25 14:44:33 alvherre Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -7099,7 +7099,7 @@ ParseLongOption(const char *string, char **name, char **value)
 
 
 /*
- * Handle options fetched from pg_database.datconfig, pg_authid.rolconfig,
+ * Handle options fetched from pg_db_role_setting.setconfig,
  * pg_proc.proconfig, etc.     Caller must specify proper context/source/action.
  *
  * The array parameter must be an array of TEXT (it must not be NULL).
@@ -7151,6 +7151,7 @@ ProcessGUCArray(ArrayType *array,
                free(name);
                if (value)
                        free(value);
+               pfree(s);
        }
 }
 
@@ -7285,6 +7286,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
                        && val[strlen(name)] == '=')
                        continue;
 
+
                /* else add it to the output array */
                if (newarray)
                {
@@ -7307,6 +7309,85 @@ GUCArrayDelete(ArrayType *array, const char *name)
        return newarray;
 }
 
+/*
+ * Given a GUC array, delete all settings from it that our permission
+ * level allows: if superuser, delete them all; if regular user, only
+ * those that are PGC_USERSET
+ */
+ArrayType *
+GUCArrayReset(ArrayType *array)
+{
+       ArrayType  *newarray;
+       int                     i;
+       int                     index;
+
+       /* if array is currently null, nothing to do */
+       if (!array)
+               return NULL;
+
+       /* if we're superuser, we can delete everything */
+       if (superuser())
+               return NULL;
+
+       newarray = NULL;
+       index = 1;
+
+       for (i = 1; i <= ARR_DIMS(array)[0]; i++)
+       {
+               Datum           d;
+               char       *val;
+               char       *eqsgn;
+               bool            isnull;
+               struct config_generic *gconf;
+
+               d = array_ref(array, 1, &i,
+                                         -1 /* varlenarray */ ,
+                                         -1 /* TEXT's typlen */ ,
+                                         false /* TEXT's typbyval */ ,
+                                         'i' /* TEXT's typalign */ ,
+                                         &isnull);
+
+               if (isnull)
+                       continue;
+               val = TextDatumGetCString(d);
+
+               eqsgn = strchr(val, '=');
+               *eqsgn = '\0';
+
+               gconf = find_option(val, false, WARNING);
+               if (!gconf)
+                       continue;
+
+               /* note: superuser-ness was already checked above */
+               /* skip entry if OK to delete */
+               if (gconf->context == PGC_USERSET)
+                       continue;
+
+               /* XXX do we need to worry about database owner? */
+
+               /* else add it to the output array */
+               if (newarray)
+               {
+                       newarray = array_set(newarray, 1, &index,
+                                                                d,
+                                                                false,
+                                                                -1 /* varlenarray */ ,
+                                                                -1 /* TEXT's typlen */ ,
+                                                                false /* TEXT's typbyval */ ,
+                                                                'i' /* TEXT's typalign */ );
+               }
+               else
+                       newarray = construct_array(&d, 1,
+                                                                          TEXTOID,
+                                                                          -1, false, 'i');
+
+               index++;
+               pfree(val);
+       }
+
+       return newarray;
+}
+
 
 /*
  * assign_hook and show_hook subroutines
index 40bbe98..9eb37b8 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.112 2010/01/26 16:33:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.113 2010/03/25 14:44:34 alvherre Exp $
  *--------------------------------------------------------------------
  */
 #ifndef GUC_H
@@ -284,6 +284,7 @@ extern void ProcessGUCArray(ArrayType *array,
                                GucContext context, GucSource source, GucAction action);
 extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
 extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
+extern ArrayType *GUCArrayReset(ArrayType *array);
 
 extern int     GUC_complaint_elevel(GucSource source);