Hi,

On Fri, Jan 17, 2025 at 10:03:17AM +0100, Laurenz Albe wrote:
> On Thu, 2024-10-31 at 22:47 +0100, Michael Banck wrote:
> > Even though there has not been a lot of discussion on this, here is a
> > rebased patch.  I have also added it to the upcoming commitfest.
> 
> I had a look at the patch.

Thanks! And sorry for the long delay...
 
> > --- a/doc/src/sgml/user-manag.sgml
> > +++ b/doc/src/sgml/user-manag.sgml
> > @@ -669,6 +669,17 @@ GRANT pg_signal_backend TO admin_user;
> >       </listitem>
> >      </varlistentry>
> >  
> > +    <varlistentry id="predefined-role-pg-manage-extensions" 
> > xreflabel="pg_manage_extensions">
> > +     <term><varname>pg_manage_extensions</varname></term>
> > +     <listitem>
> > +      <para>
> > +       <literal>pg_manage_extensions</literal> allows creating, removing or
> > +       updating extensions, even if the extensions are untrusted or the 
> > user is
> > +       not the database owner.
> > +      </para>
> > +     </listitem>
> > +    </varlistentry>
> > +
> 
> The inaccuracy of the database owner has already been mentioned.

Right, I had already changed that in my tree but never sent out an
updated version with this.
 
> Should we say "creating, altering or dropping extensions" to make the 
> connection to
> the respective commands obvious?

Alright, did so.

> > --- a/src/backend/commands/extension.c
> > +++ b/src/backend/commands/extension.c
> > @@ -994,13 +994,14 @@ execute_extension_script(Oid extensionOid, 
> > ExtensionControlFile *control,
> >     ListCell   *lc2;
> >  
> >     /*
> > -    * Enforce superuser-ness if appropriate.  We postpone these checks 
> > until
> > -    * here so that the control flags are correctly associated with the 
> > right
> > +    * Enforce superuser-ness/membership of the pg_manage_extensions
> > +    * predefined role if appropriate.  We postpone these checks until here
> > +    * so that the control flags are correctly associated with the right
> >      * script(s) if they happen to be set in secondary control files.
> >      */
> 
> This is just an attempt to improve the English:
> 
>   If appropriate, enforce superuser-ness or membership of the predefined role
>   pg_manage_extensions.

Done.

> > -                    : errhint("Must be superuser to create this 
> > extension.")));
> > +                    : errhint("Only roles with privileges of the \"%s\" 
> > role are allowed to create this extension.", "pg_manage_extensions")));
> 
> I don't see the point of breaking out the role name from the message.
> We don't do that in other places.

We actually do, I think I modelled it after other predefined roles,
e.g.:

|src/backend/commands/subscriptioncmds.c:                                
errdetail("Only roles with privileges of the \"%s\" role may create 
subscriptions.",
|src/backend/commands/subscriptioncmds.c-                                       
           "pg_create_subscription")));
|--
|src/backend/commands/copy.c:                                            
errdetail("Only roles with privileges of the \"%s\" role may COPY to or from an 
external program.",
|src/backend/commands/copy.c-                                                   
           "pg_execute_server_program"),
|--
|src/backend/commands/copy.c:                                            
errdetail("Only roles with privileges of the \"%s\" role may COPY from a file.",
|src/backend/commands/copy.c-                                                   
           "pg_read_server_files"),
|--
|src/backend/commands/copy.c:                                            
errdetail("Only roles with privileges of the \"%s\" role may COPY to a file.",
|src/backend/commands/copy.c-                                                   
           "pg_write_server_files"),

However, those are all errdetail, while the previous "Must be superuser
to [...]" is errhint, and that error message has different hints based
on whether the extension is trusted or not...

> Besides, I think that the mention of the superuser should be retained.
> Moreover, I think that commit 8d9978a717 pretty much established that we
> should not quote names if they contain underscores.
> Perhaps:
> 
>   errhint("Must be superuser or member of pg_manage_extensions to create this 
> extension.")));

Alright, I think it makes more sense to have it like that than the
above, so changed it to that.

New version 3 attached.


Michael
>From 57e02d95ace2a390ea1e40266735529f313b31ec Mon Sep 17 00:00:00 2001
From: Michael Banck <michael.ba...@credativ.de>
Date: Thu, 31 Oct 2024 22:36:12 +0100
Subject: [PATCH v3] Add new pg_manage_extensions predefined role.

This allows any role that is granted this new predefined role to CREATE, UPDATE
or DROP extensions, no matter whether they are trusted or not.
---
 doc/src/sgml/user-manag.sgml      | 11 +++++++++++
 src/backend/commands/extension.c  | 11 ++++++-----
 src/include/catalog/pg_authid.dat |  5 +++++
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index ed18704a9c2..2a44f41da4f 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -669,6 +669,17 @@ GRANT pg_signal_backend TO admin_user;
      </listitem>
     </varlistentry>
 
+    <varlistentry id="predefined-role-pg-manage-extensions" xreflabel="pg_manage_extensions">
+     <term><varname>pg_manage_extensions</varname></term>
+     <listitem>
+      <para>
+       <literal>pg_manage_extensions</literal> allows creating, altering or
+       dropping extensions, even if the extensions are untrusted or the user
+       does not have <literal>CREATE</literal> rights on the database.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry id="predefined-role-pg-monitor" xreflabel="pg_monitor">
      <term><varname>pg_monitor</varname></term>
      <term><varname>pg_read_all_settings</varname></term>
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index d9bb4ce5f1e..2426c3e0eda 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -996,13 +996,14 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 	ListCell   *lc2;
 
 	/*
-	 * Enforce superuser-ness if appropriate.  We postpone these checks until
-	 * here so that the control flags are correctly associated with the right
+	 * Enforce superuser-ness/membership of the pg_manage_extensions
+	 * predefined role if appropriate.  We postpone these checks until here
+	 * so that the control flags are correctly associated with the right
 	 * script(s) if they happen to be set in secondary control files.
 	 */
 	if (control->superuser && !superuser())
 	{
-		if (extension_is_trusted(control))
+		if (extension_is_trusted(control) || has_privs_of_role(GetUserId(), ROLE_PG_MANAGE_EXTENSIONS))
 			switch_to_superuser = true;
 		else if (from_version == NULL)
 			ereport(ERROR,
@@ -1011,7 +1012,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 							control->name),
 					 control->trusted
 					 ? errhint("Must have CREATE privilege on current database to create this extension.")
-					 : errhint("Must be superuser to create this extension.")));
+					 : errhint("Must be superuser or member of pg_manage_extensions to create this extension.")));
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -1019,7 +1020,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 							control->name),
 					 control->trusted
 					 ? errhint("Must have CREATE privilege on current database to update this extension.")
-					 : errhint("Must be superuser to update this extension.")));
+					 : errhint("Must be superuser or member of pg_manage_extensions to update this extension.")));
 	}
 
 	filename = get_extension_script_filename(control, from_version, version);
diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat
index eb4dab5c6aa..0e3eb20e2b9 100644
--- a/src/include/catalog/pg_authid.dat
+++ b/src/include/catalog/pg_authid.dat
@@ -104,5 +104,10 @@
   rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
   rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
   rolpassword => '_null_', rolvaliduntil => '_null_' },
+{ oid => '8801', oid_symbol => 'ROLE_PG_MANAGE_EXTENSIONS',
+  rolname => 'pg_manage_extensions', rolsuper => 'f', rolinherit => 't',
+  rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
+  rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
+  rolpassword => '_null_', rolvaliduntil => '_null_' },
 
 ]
-- 
2.39.5

Reply via email to