Allow pg_dumpall to dump roles w/o user passwords
authorSimon Riggs <simon@2ndQuadrant.com>
Tue, 7 Mar 2017 14:00:54 +0000 (22:00 +0800)
committerSimon Riggs <simon@2ndQuadrant.com>
Tue, 7 Mar 2017 14:00:54 +0000 (22:00 +0800)
Add new option --no-role-passwords which dumps roles without passwords.
Since we don’t need passwords, we choose to use pg_roles in preference
to pg_authid since access may be restricted for security reasons in
some configrations.

Robins Tharakan and Simon Riggs

doc/src/sgml/ref/pg_dumpall.sgml
src/bin/pg_dump/pg_dumpall.c

index 97168a08159d5c9ef68b0b15de9aa14c1d755abd..afbadce2476453efb2f8e1644976504f710cea14 100644 (file)
@@ -332,6 +332,19 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>--no-role-passwords</option></term>
+      <listitem>
+       <para>
+        Do not dump passwords for roles. When restored, roles will have a NULL
+        password and authentication will always fail until the password is reset.
+        Since password values aren't needed when this option is specified we
+        use the catalog view pg_roles in preference to pg_authid, since access
+        to pg_authid may be restricted by security policy.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>--no-security-labels</option></term>
       <listitem>
index f4b4d7bd9b64d1428f4690a3b6a4039edaabb95d..81ed924b9f3f1eedcf092379bd60e7a6605ac417 100644 (file)
@@ -74,8 +74,13 @@ static int   no_tablespaces = 0;
 static int     use_setsessauth = 0;
 static int     no_security_labels = 0;
 static int     no_unlogged_table_data = 0;
+static int     no_role_passwords = 0;
 static int     server_version;
 
+static char role_catalog[10];
+#define PG_AUTHID "pg_authid"
+#define PG_ROLES  "pg_roles "
+
 static FILE *OPF;
 static char *filename = NULL;
 
@@ -123,6 +128,7 @@ main(int argc, char *argv[])
                {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
                {"no-security-labels", no_argument, &no_security_labels, 1},
                {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
+               {"no-role-passwords", no_argument, &no_role_passwords, 1},
 
                {NULL, 0, NULL, 0}
        };
@@ -342,6 +348,25 @@ main(int argc, char *argv[])
                exit_nicely(1);
        }
 
+       if (no_role_passwords && binary_upgrade)
+       {
+               fprintf(stderr, _("%s: options --no-role-passwords and --binary-upgrade cannot be used together\n"),
+                               progname);
+               fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+                               progname);
+               exit_nicely(1);
+       }
+
+       /*
+        * If password values are not required in the dump, switch to
+        * using pg_roles which is equally useful, just more likely
+        * to have unrestricted access than pg_authid.
+        */
+       if (no_role_passwords)
+               sprintf(role_catalog, "%s", PG_ROLES);
+       else
+               sprintf(role_catalog, "%s", PG_AUTHID);
+
        /* Add long options to the pg_dump argument list */
        if (binary_upgrade)
                appendPQExpBufferStr(pgdumpopts, " --binary-upgrade");
@@ -563,6 +588,7 @@ help(void)
        printf(_("  --no-security-labels         do not dump security label assignments\n"));
        printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
        printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
+       printf(_("  --no-role-passwords          do not dump passwords for roles\n"));
        printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
        printf(_("  --use-set-session-authorization\n"
                         "                               use SET SESSION AUTHORIZATION commands instead of\n"
@@ -590,23 +616,24 @@ help(void)
 static void
 dropRoles(PGconn *conn)
 {
+       PQExpBuffer buf = createPQExpBuffer();
        PGresult   *res;
        int                     i_rolname;
        int                     i;
 
        if (server_version >= 90600)
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT rolname "
-                                                  "FROM pg_authid "
+                                                  "FROM %s "
                                                   "WHERE rolname !~ '^pg_' "
-                                                  "ORDER BY 1");
+                                                  "ORDER BY 1", role_catalog);
        else if (server_version >= 80100)
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT rolname "
-                                                  "FROM pg_authid "
-                                                  "ORDER BY 1");
+                                                  "FROM %s "
+                                                  "ORDER BY 1", role_catalog);
        else
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT usename as rolname "
                                                   "FROM pg_shadow "
                                                   "UNION "
@@ -614,6 +641,8 @@ dropRoles(PGconn *conn)
                                                   "FROM pg_group "
                                                   "ORDER BY 1");
 
+       res = executeQuery(conn, buf->data);
+
        i_rolname = PQfnumber(res, "rolname");
 
        if (PQntuples(res) > 0)
@@ -631,6 +660,7 @@ dropRoles(PGconn *conn)
        }
 
        PQclear(res);
+       destroyPQExpBuffer(buf);
 
        fprintf(OPF, "\n\n");
 }
@@ -666,21 +696,21 @@ dumpRoles(PGconn *conn)
                                                  "rolcreaterole, rolcreatedb, "
                                                  "rolcanlogin, rolconnlimit, rolpassword, "
                                                  "rolvaliduntil, rolreplication, rolbypassrls, "
-                        "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
+                        "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
                                                  "rolname = current_user AS is_current_user "
-                                                 "FROM pg_authid "
+                                                 "FROM %s "
                                                  "WHERE rolname !~ '^pg_' "
-                                                 "ORDER BY 2");
+                                                 "ORDER BY 2", role_catalog, role_catalog);
        else if (server_version >= 90500)
                printfPQExpBuffer(buf,
                                                  "SELECT oid, rolname, rolsuper, rolinherit, "
                                                  "rolcreaterole, rolcreatedb, "
                                                  "rolcanlogin, rolconnlimit, rolpassword, "
                                                  "rolvaliduntil, rolreplication, rolbypassrls, "
-                        "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
+                        "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
                                                  "rolname = current_user AS is_current_user "
-                                                 "FROM pg_authid "
-                                                 "ORDER BY 2");
+                                                 "FROM %s "
+                                                 "ORDER BY 2", role_catalog, role_catalog);
        else if (server_version >= 90100)
                printfPQExpBuffer(buf,
                                                  "SELECT oid, rolname, rolsuper, rolinherit, "
@@ -688,10 +718,10 @@ dumpRoles(PGconn *conn)
                                                  "rolcanlogin, rolconnlimit, rolpassword, "
                                                  "rolvaliduntil, rolreplication, "
                                                  "false as rolbypassrls, "
-                        "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
+                        "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
                                                  "rolname = current_user AS is_current_user "
-                                                 "FROM pg_authid "
-                                                 "ORDER BY 2");
+                                                 "FROM %s "
+                                                 "ORDER BY 2", role_catalog, role_catalog);
        else if (server_version >= 80200)
                printfPQExpBuffer(buf,
                                                  "SELECT oid, rolname, rolsuper, rolinherit, "
@@ -699,10 +729,10 @@ dumpRoles(PGconn *conn)
                                                  "rolcanlogin, rolconnlimit, rolpassword, "
                                                  "rolvaliduntil, false as rolreplication, "
                                                  "false as rolbypassrls, "
-                        "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
+                        "pg_catalog.shobj_description(oid, '%s') as rolcomment, "
                                                  "rolname = current_user AS is_current_user "
-                                                 "FROM pg_authid "
-                                                 "ORDER BY 2");
+                                                 "FROM %s "
+                                                 "ORDER BY 2", role_catalog, role_catalog);
        else if (server_version >= 80100)
                printfPQExpBuffer(buf,
                                                  "SELECT oid, rolname, rolsuper, rolinherit, "
@@ -712,8 +742,8 @@ dumpRoles(PGconn *conn)
                                                  "false as rolbypassrls, "
                                                  "null as rolcomment, "
                                                  "rolname = current_user AS is_current_user "
-                                                 "FROM pg_authid "
-                                                 "ORDER BY 2");
+                                                 "FROM %s "
+                                                 "ORDER BY 2", role_catalog);
        else
                printfPQExpBuffer(buf,
                                                  "SELECT 0 as oid, usename as rolname, "
@@ -846,7 +876,8 @@ dumpRoles(PGconn *conn)
                        appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
                                                          PQgetvalue(res, i, i_rolconnlimit));
 
-               if (!PQgetisnull(res, i, i_rolpassword))
+
+               if (!PQgetisnull(res, i, i_rolpassword) && !no_role_passwords)
                {
                        appendPQExpBufferStr(buf, " PASSWORD ");
                        appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
@@ -897,19 +928,21 @@ dumpRoles(PGconn *conn)
 static void
 dumpRoleMembership(PGconn *conn)
 {
+       PQExpBuffer buf = createPQExpBuffer();
        PGresult   *res;
        int                     i;
 
-       res = executeQuery(conn, "SELECT ur.rolname AS roleid, "
+       printfPQExpBuffer(buf, "SELECT ur.rolname AS roleid, "
                                           "um.rolname AS member, "
                                           "a.admin_option, "
                                           "ug.rolname AS grantor "
                                           "FROM pg_auth_members a "
-                                          "LEFT JOIN pg_authid ur on ur.oid = a.roleid "
-                                          "LEFT JOIN pg_authid um on um.oid = a.member "
-                                          "LEFT JOIN pg_authid ug on ug.oid = a.grantor "
+                                          "LEFT JOIN %s ur on ur.oid = a.roleid "
+                                          "LEFT JOIN %s um on um.oid = a.member "
+                                          "LEFT JOIN %s ug on ug.oid = a.grantor "
                                        "WHERE NOT (ur.rolname ~ '^pg_' AND um.rolname ~ '^pg_')"
-                                          "ORDER BY 1,2,3");
+                                          "ORDER BY 1,2,3", role_catalog, role_catalog, role_catalog);
+       res = executeQuery(conn, buf->data);
 
        if (PQntuples(res) > 0)
                fprintf(OPF, "--\n-- Role memberships\n--\n\n");
@@ -939,6 +972,7 @@ dumpRoleMembership(PGconn *conn)
        }
 
        PQclear(res);
+       destroyPQExpBuffer(buf);
 
        fprintf(OPF, "\n\n");
 }
@@ -1298,9 +1332,9 @@ dumpCreateDB(PGconn *conn)
         * databases.
         */
        if (server_version >= 90600)
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT datname, "
-                                                  "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
+                                                  "coalesce(rolname, (select rolname from %s where oid=(select datdba from pg_database where datname='template0'))), "
                                                   "pg_encoding_to_char(d.encoding), "
                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
                                                   "datistemplate, "
@@ -1314,43 +1348,43 @@ dumpCreateDB(PGconn *conn)
                                                   "AS rdatacl, "
                                                   "datconnlimit, "
                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
-                         "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
-                                                  "WHERE datallowconn ORDER BY 1");
+                         "FROM pg_database d LEFT JOIN %s u ON (datdba = u.oid) "
+                                                  "WHERE datallowconn ORDER BY 1", role_catalog, role_catalog);
        else if (server_version >= 90300)
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT datname, "
-                                                  "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
+                                                  "coalesce(rolname, (select rolname from %s where oid=(select datdba from pg_database where datname='template0'))), "
                                                   "pg_encoding_to_char(d.encoding), "
                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
                                                   "datistemplate, datacl, '' as rdatacl, "
                                                   "datconnlimit, "
                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
-                         "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
-                                                  "WHERE datallowconn ORDER BY 1");
+                         "FROM pg_database d LEFT JOIN %s u ON (datdba = u.oid) "
+                                                  "WHERE datallowconn ORDER BY 1", role_catalog, role_catalog);
        else if (server_version >= 80400)
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT datname, "
-                                                  "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
+                                                  "coalesce(rolname, (select rolname from %s where oid=(select datdba from pg_database where datname='template0'))), "
                                                   "pg_encoding_to_char(d.encoding), "
                                          "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
                                                   "datistemplate, datacl, '' as rdatacl, "
                                                   "datconnlimit, "
                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
-                         "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
-                                                  "WHERE datallowconn ORDER BY 1");
+                         "FROM pg_database d LEFT JOIN %s u ON (datdba = u.oid) "
+                                                  "WHERE datallowconn ORDER BY 1", role_catalog, role_catalog);
        else if (server_version >= 80100)
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT datname, "
-                                                  "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
+                                                  "coalesce(rolname, (select rolname from %s where oid=(select datdba from pg_database where datname='template0'))), "
                                                   "pg_encoding_to_char(d.encoding), "
                                                   "null::text AS datcollate, null::text AS datctype, datfrozenxid, 0 AS datminmxid, "
                                                   "datistemplate, datacl, '' as rdatacl, "
                                                   "datconnlimit, "
                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
-                         "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
-                                                  "WHERE datallowconn ORDER BY 1");
+                         "FROM pg_database d LEFT JOIN %s u ON (datdba = u.oid) "
+                                                  "WHERE datallowconn ORDER BY 1", role_catalog, role_catalog);
        else
-               res = executeQuery(conn,
+               printfPQExpBuffer(buf,
                                                   "SELECT datname, "
                                                   "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
                                                   "pg_encoding_to_char(d.encoding), "
@@ -1361,6 +1395,8 @@ dumpCreateDB(PGconn *conn)
                   "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
                                                   "WHERE datallowconn ORDER BY 1");
 
+       res = executeQuery(conn, buf->data);
+
        for (i = 0; i < PQntuples(res); i++)
        {
                char       *dbname = PQgetvalue(res, i, 0);
@@ -1557,9 +1593,9 @@ dumpUserConfig(PGconn *conn, const char *username)
                if (server_version >= 90000)
                        printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting WHERE "
                                                          "setdatabase = 0 AND setrole = "
-                                          "(SELECT oid FROM pg_authid WHERE rolname = ", count);
+                                          "(SELECT oid FROM %s WHERE rolname = ", count, role_catalog);
                else if (server_version >= 80100)
-                       printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count);
+                       printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM %s WHERE rolname = ", count, role_catalog);
                else
                        printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
                appendStringLiteralConn(buf, username, conn);
@@ -1597,8 +1633,8 @@ dumpDbRoleConfig(PGconn *conn)
        int                     i;
 
        printfPQExpBuffer(buf, "SELECT rolname, datname, unnest(setconfig) "
-                                         "FROM pg_db_role_setting, pg_authid, pg_database "
-                 "WHERE setrole = pg_authid.oid AND setdatabase = pg_database.oid");
+                                         "FROM pg_db_role_setting, %s u, pg_database "
+                 "WHERE setrole = u.oid AND setdatabase = pg_database.oid", role_catalog);
        res = executeQuery(conn, buf->data);
 
        if (PQntuples(res) > 0)