Skip to content

Commit be8cebc

Browse files
committed
Prevent ALTER USER f RESET ALL from removing the settings that were put there
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.
1 parent 92fc0db commit be8cebc

File tree

4 files changed

+124
-13
lines changed

4 files changed

+124
-13
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.223 2010/02/17 04:19:37 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.224 2010/03/25 14:44:33 alvherre Exp $ -->
22
<!--
33
Documentation of the system catalogs, directed toward PostgreSQL developers
44
-->
@@ -1188,12 +1188,6 @@
11881188
<entry>Password expiry time (only used for password authentication);
11891189
NULL if no expiration</entry>
11901190
</row>
1191-
1192-
<row>
1193-
<entry><structfield>rolconfig</structfield></entry>
1194-
<entry><type>text[]</type></entry>
1195-
<entry>Session defaults for run-time configuration variables</entry>
1196-
</row>
11971191
</tbody>
11981192
</tgroup>
11991193
</table>

src/backend/catalog/pg_db_role_setting.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.3 2010/02/26 02:00:37 momjian Exp $
9+
* $PostgreSQL: pgsql/src/backend/catalog/pg_db_role_setting.c,v 1.4 2010/03/25 14:44:33 alvherre Exp $
1010
*/
1111
#include "postgres.h"
1212

@@ -49,7 +49,8 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
4949
/*
5050
* There are three cases:
5151
*
52-
* - in RESET ALL, simply delete the pg_db_role_setting tuple (if any)
52+
* - in RESET ALL, request GUC to reset the settings array and update the
53+
* catalog if there's anything left, delete it otherwise
5354
*
5455
* - in other commands, if there's a tuple in pg_db_role_setting, update
5556
* it; if it ends up empty, delete it
@@ -60,7 +61,41 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
6061
if (setstmt->kind == VAR_RESET_ALL)
6162
{
6263
if (HeapTupleIsValid(tuple))
63-
simple_heap_delete(rel, &tuple->t_self);
64+
{
65+
ArrayType *new = NULL;
66+
Datum datum;
67+
bool isnull;
68+
69+
datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig,
70+
RelationGetDescr(rel), &isnull);
71+
72+
if (!isnull)
73+
new = GUCArrayReset(DatumGetArrayTypeP(datum));
74+
75+
if (new)
76+
{
77+
Datum repl_val[Natts_pg_db_role_setting];
78+
bool repl_null[Natts_pg_db_role_setting];
79+
bool repl_repl[Natts_pg_db_role_setting];
80+
HeapTuple newtuple;
81+
82+
memset(repl_repl, false, sizeof(repl_repl));
83+
84+
repl_val[Anum_pg_db_role_setting_setconfig - 1] =
85+
PointerGetDatum(new);
86+
repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true;
87+
repl_null[Anum_pg_db_role_setting_setconfig - 1] = false;
88+
89+
newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
90+
repl_val, repl_null, repl_repl);
91+
simple_heap_update(rel, &tuple->t_self, newtuple);
92+
93+
/* Update indexes */
94+
CatalogUpdateIndexes(rel, newtuple);
95+
}
96+
else
97+
simple_heap_delete(rel, &tuple->t_self);
98+
}
6499
}
65100
else if (HeapTupleIsValid(tuple))
66101
{

src/backend/utils/misc/guc.c

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Written by Peter Eisentraut <peter_e@gmx.net>.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.544 2010/03/21 00:17:59 petere Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.545 2010/03/25 14:44:33 alvherre Exp $
1414
*
1515
*--------------------------------------------------------------------
1616
*/
@@ -7099,7 +7099,7 @@ ParseLongOption(const char *string, char **name, char **value)
70997099

71007100

71017101
/*
7102-
* Handle options fetched from pg_database.datconfig, pg_authid.rolconfig,
7102+
* Handle options fetched from pg_db_role_setting.setconfig,
71037103
* pg_proc.proconfig, etc. Caller must specify proper context/source/action.
71047104
*
71057105
* The array parameter must be an array of TEXT (it must not be NULL).
@@ -7151,6 +7151,7 @@ ProcessGUCArray(ArrayType *array,
71517151
free(name);
71527152
if (value)
71537153
free(value);
7154+
pfree(s);
71547155
}
71557156
}
71567157

@@ -7285,6 +7286,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
72857286
&& val[strlen(name)] == '=')
72867287
continue;
72877288

7289+
72887290
/* else add it to the output array */
72897291
if (newarray)
72907292
{
@@ -7307,6 +7309,85 @@ GUCArrayDelete(ArrayType *array, const char *name)
73077309
return newarray;
73087310
}
73097311

7312+
/*
7313+
* Given a GUC array, delete all settings from it that our permission
7314+
* level allows: if superuser, delete them all; if regular user, only
7315+
* those that are PGC_USERSET
7316+
*/
7317+
ArrayType *
7318+
GUCArrayReset(ArrayType *array)
7319+
{
7320+
ArrayType *newarray;
7321+
int i;
7322+
int index;
7323+
7324+
/* if array is currently null, nothing to do */
7325+
if (!array)
7326+
return NULL;
7327+
7328+
/* if we're superuser, we can delete everything */
7329+
if (superuser())
7330+
return NULL;
7331+
7332+
newarray = NULL;
7333+
index = 1;
7334+
7335+
for (i = 1; i <= ARR_DIMS(array)[0]; i++)
7336+
{
7337+
Datum d;
7338+
char *val;
7339+
char *eqsgn;
7340+
bool isnull;
7341+
struct config_generic *gconf;
7342+
7343+
d = array_ref(array, 1, &i,
7344+
-1 /* varlenarray */ ,
7345+
-1 /* TEXT's typlen */ ,
7346+
false /* TEXT's typbyval */ ,
7347+
'i' /* TEXT's typalign */ ,
7348+
&isnull);
7349+
7350+
if (isnull)
7351+
continue;
7352+
val = TextDatumGetCString(d);
7353+
7354+
eqsgn = strchr(val, '=');
7355+
*eqsgn = '\0';
7356+
7357+
gconf = find_option(val, false, WARNING);
7358+
if (!gconf)
7359+
continue;
7360+
7361+
/* note: superuser-ness was already checked above */
7362+
/* skip entry if OK to delete */
7363+
if (gconf->context == PGC_USERSET)
7364+
continue;
7365+
7366+
/* XXX do we need to worry about database owner? */
7367+
7368+
/* else add it to the output array */
7369+
if (newarray)
7370+
{
7371+
newarray = array_set(newarray, 1, &index,
7372+
d,
7373+
false,
7374+
-1 /* varlenarray */ ,
7375+
-1 /* TEXT's typlen */ ,
7376+
false /* TEXT's typbyval */ ,
7377+
'i' /* TEXT's typalign */ );
7378+
}
7379+
else
7380+
newarray = construct_array(&d, 1,
7381+
TEXTOID,
7382+
-1, false, 'i');
7383+
7384+
index++;
7385+
pfree(val);
7386+
}
7387+
7388+
return newarray;
7389+
}
7390+
73107391

73117392
/*
73127393
* assign_hook and show_hook subroutines

src/include/utils/guc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Copyright (c) 2000-2010, PostgreSQL Global Development Group
88
* Written by Peter Eisentraut <peter_e@gmx.net>.
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.112 2010/01/26 16:33:40 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.113 2010/03/25 14:44:34 alvherre Exp $
1111
*--------------------------------------------------------------------
1212
*/
1313
#ifndef GUC_H
@@ -284,6 +284,7 @@ extern void ProcessGUCArray(ArrayType *array,
284284
GucContext context, GucSource source, GucAction action);
285285
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
286286
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
287+
extern ArrayType *GUCArrayReset(ArrayType *array);
287288

288289
extern int GUC_complaint_elevel(GucSource source);
289290

0 commit comments

Comments
 (0)