diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/transam/xlog.c | 8 | ||||
-rw-r--r-- | src/backend/catalog/system_views.sql | 3 | ||||
-rw-r--r-- | src/backend/commands/user.c | 46 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 20 | ||||
-rw-r--r-- | src/backend/utils/init/miscinit.c | 19 | ||||
-rw-r--r-- | src/backend/utils/init/postinit.c | 6 |
6 files changed, 91 insertions, 11 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b49b933de3e..bf62138bf86 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8301,10 +8301,10 @@ pg_start_backup(PG_FUNCTION_ARGS) struct stat stat_buf; FILE *fp; - if (!superuser()) + if (!superuser() && !is_authenticated_user_replication_role()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to run a backup"))); + errmsg("must be superuser or replication role to run a backup"))); if (RecoveryInProgress()) ereport(ERROR, @@ -8493,10 +8493,10 @@ pg_stop_backup(PG_FUNCTION_ARGS) int waits = 0; bool reported_waiting = false; - if (!superuser()) + if (!superuser() && !is_authenticated_user_replication_role()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - (errmsg("must be superuser to run a backup")))); + (errmsg("must be superuser or replication role to run a backup")))); if (RecoveryInProgress()) ereport(ERROR, diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 346eaaf8924..e0e7efdf5d4 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -15,6 +15,7 @@ CREATE VIEW pg_roles AS rolcreatedb, rolcatupdate, rolcanlogin, + rolreplication, rolconnlimit, '********'::text as rolpassword, rolvaliduntil, @@ -30,6 +31,7 @@ CREATE VIEW pg_shadow AS rolcreatedb AS usecreatedb, rolsuper AS usesuper, rolcatupdate AS usecatupd, + rolreplication AS userepl, rolpassword AS passwd, rolvaliduntil::abstime AS valuntil, setconfig AS useconfig @@ -54,6 +56,7 @@ CREATE VIEW pg_user AS usecreatedb, usesuper, usecatupd, + userepl, '********'::text as passwd, valuntil, useconfig diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 2634ca10e64..df83cdea2cf 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -94,6 +94,7 @@ CreateRole(CreateRoleStmt *stmt) bool createrole = false; /* Can this user create roles? */ bool createdb = false; /* Can the user create databases? */ bool canlogin = false; /* Can this user login? */ + bool isreplication = false; /* Is this a replication role? */ int connlimit = -1; /* maximum connections allowed */ List *addroleto = NIL; /* roles to make this a member of */ List *rolemembers = NIL; /* roles to be members of this role */ @@ -107,6 +108,7 @@ CreateRole(CreateRoleStmt *stmt) DefElem *dcreaterole = NULL; DefElem *dcreatedb = NULL; DefElem *dcanlogin = NULL; + DefElem *disreplication = NULL; DefElem *dconnlimit = NULL; DefElem *daddroleto = NULL; DefElem *drolemembers = NULL; @@ -190,6 +192,14 @@ CreateRole(CreateRoleStmt *stmt) errmsg("conflicting or redundant options"))); dcanlogin = defel; } + else if (strcmp(defel->defname, "isreplication") == 0) + { + if (disreplication) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + disreplication = defel; + } else if (strcmp(defel->defname, "connectionlimit") == 0) { if (dconnlimit) @@ -247,6 +257,8 @@ CreateRole(CreateRoleStmt *stmt) createdb = intVal(dcreatedb->arg) != 0; if (dcanlogin) canlogin = intVal(dcanlogin->arg) != 0; + if (disreplication) + isreplication = intVal(disreplication->arg) != 0; if (dconnlimit) { connlimit = intVal(dconnlimit->arg); @@ -272,6 +284,13 @@ CreateRole(CreateRoleStmt *stmt) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create superusers"))); } + else if (isreplication) + { + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to create replication users"))); + } else { if (!have_createrole_privilege()) @@ -341,6 +360,7 @@ CreateRole(CreateRoleStmt *stmt) /* superuser gets catupdate right by default */ new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper); new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin); + new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication); new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit); if (password) @@ -439,6 +459,7 @@ AlterRole(AlterRoleStmt *stmt) int createrole = -1; /* Can this user create roles? */ int createdb = -1; /* Can the user create databases? */ int canlogin = -1; /* Can this user login? */ + int isreplication = -1; /* Is this a replication role? */ int connlimit = -1; /* maximum connections allowed */ List *rolemembers = NIL; /* roles to be added/removed */ char *validUntil = NULL; /* time the login is valid until */ @@ -450,6 +471,7 @@ AlterRole(AlterRoleStmt *stmt) DefElem *dcreaterole = NULL; DefElem *dcreatedb = NULL; DefElem *dcanlogin = NULL; + DefElem *disreplication = NULL; DefElem *dconnlimit = NULL; DefElem *drolemembers = NULL; DefElem *dvalidUntil = NULL; @@ -514,6 +536,14 @@ AlterRole(AlterRoleStmt *stmt) errmsg("conflicting or redundant options"))); dcanlogin = defel; } + else if (strcmp(defel->defname, "isreplication") == 0) + { + if (disreplication) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + disreplication = defel; + } else if (strcmp(defel->defname, "connectionlimit") == 0) { if (dconnlimit) @@ -556,6 +586,8 @@ AlterRole(AlterRoleStmt *stmt) createdb = intVal(dcreatedb->arg); if (dcanlogin) canlogin = intVal(dcanlogin->arg); + if (disreplication) + isreplication = intVal(disreplication->arg); if (dconnlimit) { connlimit = intVal(dconnlimit->arg); @@ -594,12 +626,20 @@ AlterRole(AlterRoleStmt *stmt) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to alter superusers"))); } + else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0) + { + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to alter replication users"))); + } else if (!have_createrole_privilege()) { if (!(inherit < 0 && createrole < 0 && createdb < 0 && canlogin < 0 && + isreplication < 0 && !dconnlimit && !rolemembers && !validUntil && @@ -685,6 +725,12 @@ AlterRole(AlterRoleStmt *stmt) new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true; } + if (isreplication >= 0) + { + new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0); + new_record_repl[Anum_pg_authid_rolreplication - 1] = true; + } + if (dconnlimit) { new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 8fc79b63377..37840baa0f6 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -510,8 +510,9 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NOCREATEDB - NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER - NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC + NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOREPLICATION_P + NOSUPERUSER NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF + NULLS_P NUMERIC OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER @@ -523,8 +524,9 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ QUOTE RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REINDEX - RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART - RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE + RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA REPLICATION_P + RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK + ROW ROWS RULE SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE @@ -864,6 +866,14 @@ AlterOptRoleElem: { $$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE)); } + | REPLICATION_P + { + $$ = makeDefElem("isreplication", (Node *)makeInteger(TRUE)); + } + | NOREPLICATION_P + { + $$ = makeDefElem("isreplication", (Node *)makeInteger(FALSE)); + } | CONNECTION LIMIT SignedIconst { $$ = makeDefElem("connectionlimit", (Node *)makeInteger($3)); @@ -11288,6 +11298,7 @@ unreserved_keyword: | NOCREATEUSER | NOINHERIT | NOLOGIN_P + | NOREPLICATION_P | NOSUPERUSER | NOTHING | NOTIFY @@ -11330,6 +11341,7 @@ unreserved_keyword: | REPEATABLE | REPLACE | REPLICA + | REPLICATION_P | RESET | RESTART | RESTRICT diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index d74b5ccb30d..0d5ffb0a8e5 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -231,6 +231,7 @@ static int SecurityRestrictionContext = 0; static bool SetRoleIsActive = false; + /* * GetUserId - get the current effective user ID. * @@ -389,6 +390,24 @@ SetUserIdAndContext(Oid userid, bool sec_def_context) /* + * Check if the authenticated user is a replication role + */ +bool +is_authenticated_user_replication_role(void) +{ + bool result = false; + HeapTuple utup; + + utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(AuthenticatedUserId)); + if (HeapTupleIsValid(utup)) + { + result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication; + ReleaseSysCache(utup); + } + return result; +} + +/* * Initialize user identity during normal backend startup */ void diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index db06cda46e8..eaaf27ffa51 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -658,11 +658,11 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, { Assert(!bootstrap); - /* must have authenticated as a superuser */ - if (!am_superuser) + /* must have authenticated as a replication role */ + if (!is_authenticated_user_replication_role()) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to start walsender"))); + errmsg("must be replication role to start walsender"))); /* process any options passed in the startup packet */ if (MyProcPort != NULL) |