From ac10c603c70e1380c88d2ce1f0559dd35a6ae1c3 Mon Sep 17 00:00:00 2001 From: Anju Bharti <66729219+anju15bharti@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:53:30 +0530 Subject: [PATCH] Support Securityadmin fixed server role (#67) Added support for new fixed server role securityadmin. This role has following privileges with it: Members of the securityadmin fixed server role can manage logins and their properties. They can GRANT, DENY, and REVOKE server-level permissions. securityadmin can also GRANT, DENY, and REVOKE database-level permissions if they have access to a database. Original PR with all the comments babelfish-for-postgresql#2907 Issue resolved: BABEL-5040 Signed-off-by: ANJU BHARTI --- .../src/backend/tds/tdsutils.c | 13 +- contrib/babelfishpg_tds/src/include/tds_int.h | 1 + .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 13 +- contrib/babelfishpg_tsql/sql/ownership.sql | 14 +- .../babelfishpg_tsql/sql/sys_functions.sql | 4 + .../babelfishpg_tsql--4.3.0--4.4.0.sql | 256 ++- .../src/backend_parser/gram-tsql-epilogue.y.c | 21 + .../src/backend_parser/gram-tsql-prologue.y.h | 2 + .../src/backend_parser/gram-tsql-rule.y | 14 +- contrib/babelfishpg_tsql/src/catalog.h | 12 + contrib/babelfishpg_tsql/src/pl_exec-2.c | 6 +- contrib/babelfishpg_tsql/src/pl_handler.c | 88 +- contrib/babelfishpg_tsql/src/procedures.c | 96 +- contrib/babelfishpg_tsql/src/rolecmds.c | 48 +- contrib/babelfishpg_tsql/src/rolecmds.h | 1 + test/JDBC/expected/BABEL-2403.out | 4 + test/JDBC/expected/BABEL-LOGIN-USER-EXT.out | 14 +- test/JDBC/expected/BABEL-LOGIN-vu-verify.out | 4 +- .../expected/bbf_role_admin_restrictions.out | 2 +- .../expected/is_srvrolemember-vu-verify.out | 2 +- test/JDBC/expected/is_srvrolemember.out | 2 +- .../securityadmin_role-vu-cleanup.out | 63 + .../securityadmin_role-vu-prepare.out | 90 + .../expected/securityadmin_role-vu-verify.out | 1609 +++++++++++++++++ test/JDBC/expected/single_db/BABEL-2403.out | 4 + .../single_db/BABEL-LOGIN-USER-EXT.out | 14 +- .../sys-server_principals-vu-verify.out | 1 + .../input/securityadmin_role-vu-cleanup.mix | 63 + .../input/securityadmin_role-vu-prepare.mix | 90 + .../input/securityadmin_role-vu-verify.mix | 907 ++++++++++ test/JDBC/upgrade/15_5/schedule | 2 +- test/JDBC/upgrade/15_6/schedule | 2 +- test/JDBC/upgrade/15_7/schedule | 2 +- test/JDBC/upgrade/15_8/schedule | 2 +- test/JDBC/upgrade/15_9/schedule | 1 + test/JDBC/upgrade/16_1/schedule | 1 + test/JDBC/upgrade/16_2/schedule | 2 +- test/JDBC/upgrade/16_3/schedule | 1 + test/JDBC/upgrade/16_4/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + .../expected_dependency.out | 1 + 41 files changed, 3332 insertions(+), 142 deletions(-) create mode 100644 test/JDBC/expected/securityadmin_role-vu-cleanup.out create mode 100644 test/JDBC/expected/securityadmin_role-vu-prepare.out create mode 100644 test/JDBC/expected/securityadmin_role-vu-verify.out create mode 100644 test/JDBC/input/securityadmin_role-vu-cleanup.mix create mode 100644 test/JDBC/input/securityadmin_role-vu-prepare.mix create mode 100644 test/JDBC/input/securityadmin_role-vu-verify.mix diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c index dff1e6d58f..01e9c5a465 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c @@ -939,14 +939,17 @@ is_babelfish_role(const char *role) Oid bbf_master_guest_oid; Oid bbf_tempdb_guest_oid; Oid bbf_msdb_guest_oid; + Oid securityadmin_oid; sysadmin_oid = get_role_oid(BABELFISH_SYSADMIN, true); /* missing OK */ role_oid = get_role_oid(role, true); /* missing OK */ + securityadmin_oid = get_role_oid(BABELFISH_SECURITYADMIN, true); /* missing OK */ if (!OidIsValid(sysadmin_oid) || !OidIsValid(role_oid)) return false; if (is_member_of_role(sysadmin_oid, role_oid) || + is_member_of_role(securityadmin_oid, role_oid) || pg_strcasecmp(role, BABELFISH_ROLE_ADMIN) == 0) /* check if it is bbf_role_admin */ return true; @@ -1204,11 +1207,13 @@ handle_grant_role(GrantRoleStmt *grant_stmt) { ListCell *item; Oid bbf_role_admin_oid = InvalidOid; + Oid securityadmin_oid = InvalidOid; if (MyProcPort->is_tds_conn && sql_dialect == SQL_DIALECT_TSQL) return true; bbf_role_admin_oid = get_role_oid(BABELFISH_ROLE_ADMIN, false); + securityadmin_oid = get_role_oid(BABELFISH_SECURITYADMIN, false); /* * Allow GRANT ROLE if current user is bbf_role_admin as we need @@ -1218,7 +1223,7 @@ handle_grant_role(GrantRoleStmt *grant_stmt) if (bbf_role_admin_oid == GetUserId()) return true; - /* Restrict roles to added as a member of bbf_role_admin */ + /* Restrict roles to added as a member of bbf_role_admin/securityadmin */ foreach(item, grant_stmt->granted_roles) { AccessPriv *priv = (AccessPriv *) lfirst(item); @@ -1229,18 +1234,18 @@ handle_grant_role(GrantRoleStmt *grant_stmt) continue; roleid = get_role_oid(rolename, false); - if (OidIsValid(roleid) && roleid == bbf_role_admin_oid) + if (OidIsValid(roleid) && (roleid == bbf_role_admin_oid || roleid == securityadmin_oid)) check_babelfish_alterrole_restictions(false); } - /* Restrict grant to/from bbf_role_admin role */ + /* Restrict grant to/from bbf_role_admin/securityadmin role */ foreach(item, grant_stmt->grantee_roles) { RoleSpec *rolespec = lfirst_node(RoleSpec, item); Oid roleid; roleid = get_rolespec_oid(rolespec, false); - if (OidIsValid(roleid) && roleid == bbf_role_admin_oid) + if (OidIsValid(roleid) && (roleid == bbf_role_admin_oid || roleid == securityadmin_oid)) check_babelfish_alterrole_restictions(false); } diff --git a/contrib/babelfishpg_tds/src/include/tds_int.h b/contrib/babelfishpg_tds/src/include/tds_int.h index 5b7943d201..30894728d7 100644 --- a/contrib/babelfishpg_tds/src/include/tds_int.h +++ b/contrib/babelfishpg_tds/src/include/tds_int.h @@ -256,6 +256,7 @@ extern ProcessUtility_hook_type next_ProcessUtility; #define PUBLIC_ROLE_NAME "public" #define BABELFISH_SYSADMIN "sysadmin" #define BABELFISH_ROLE_ADMIN "bbf_role_admin" +#define BABELFISH_SECURITYADMIN "securityadmin" /* Functions in backend/tds/tdscomm.c */ extern void TdsSetMessageType(uint8_t msgType); diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index 10dcade293..f17e137313 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -2060,8 +2060,8 @@ BEGIN ELSIF role = 'public' COLLATE sys.database_default THEN RETURN 1; - ELSIF role = 'sysadmin' COLLATE sys.database_default THEN - has_role = pg_has_role(login::TEXT, role::TEXT, 'MEMBER'); + ELSIF role = 'sysadmin' COLLATE sys.database_default OR role = 'securityadmin' COLLATE sys.database_default THEN + has_role = (pg_has_role(login::TEXT, role::TEXT, 'MEMBER') OR pg_has_role(login::TEXT, 'sysadmin'::TEXT, 'MEMBER')); IF has_role THEN RETURN 1; ELSE @@ -2070,9 +2070,7 @@ BEGIN ELSIF role COLLATE sys.database_default IN ( 'serveradmin', - 'securityadmin', 'setupadmin', - 'securityadmin', 'processadmin', 'dbcreator', 'diskadmin', @@ -2427,7 +2425,12 @@ CAST( ELSE 0 END AS INT) AS sysadmin, -CAST(0 AS INT) AS securityadmin, +CAST( + CASE + WHEN is_srvrolemember('securityadmin', Base.name) = 1 THEN 1 + ELSE 0 + END +AS INT) AS securityadmin, CAST(0 AS INT) AS serveradmin, CAST(0 AS INT) AS setupadmin, CAST(0 AS INT) AS processadmin, diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index dbbda19e43..61f0f5eea9 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -259,7 +259,7 @@ CREATE OR REPLACE PROCEDURE initialize_babelfish ( sa_name VARCHAR(128) ) LANGUAGE plpgsql AS $$ DECLARE - reserved_roles varchar[] := ARRAY['sysadmin', 'master_dbo', 'master_guest', 'master_db_owner', 'tempdb_dbo', 'tempdb_guest', 'tempdb_db_owner', 'msdb_dbo', 'msdb_guest', 'msdb_db_owner']; + reserved_roles varchar[] := ARRAY['sysadmin', 'securityadmin', 'master_dbo', 'master_guest', 'master_db_owner', 'tempdb_dbo', 'tempdb_guest', 'tempdb_db_owner', 'msdb_dbo', 'msdb_guest', 'msdb_db_owner']; user_id oid := -1; db_name name := NULL; role_name varchar; @@ -285,11 +285,13 @@ BEGIN RAISE E'Could not initialize babelfish with given role name: % is not the DB owner of current database.', sa_name; END IF; + EXECUTE format('CREATE ROLE securityadmin CREATEROLE INHERIT PASSWORD NULL'); EXECUTE format('CREATE ROLE bbf_role_admin CREATEDB CREATEROLE INHERIT PASSWORD NULL'); EXECUTE format('GRANT CREATE ON DATABASE %s TO bbf_role_admin WITH GRANT OPTION', CURRENT_DATABASE()); EXECUTE format('GRANT %I to bbf_role_admin WITH ADMIN TRUE;', sa_name); EXECUTE format('CREATE ROLE sysadmin CREATEDB CREATEROLE INHERIT ROLE %I', sa_name); EXECUTE format('GRANT sysadmin TO bbf_role_admin WITH ADMIN TRUE'); + EXECUTE format('GRANT securityadmin TO bbf_role_admin WITH ADMIN TRUE'); EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_partition_function_seq TO sysadmin WITH GRANT OPTION'); EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_partition_scheme_seq TO sysadmin WITH GRANT OPTION'); EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_db_seq TO sysadmin WITH GRANT OPTION'); @@ -299,6 +301,7 @@ BEGIN CALL sys.babel_initialize_logins(sa_name); CALL sys.babel_initialize_logins('sysadmin'); CALL sys.babel_initialize_logins('bbf_role_admin'); + CALL sys.babel_initialize_logins('securityadmin'); CALL sys.babel_create_builtin_dbs(sa_name); CALL sys.initialize_babel_extras(); -- run analyze for all babelfish catalog @@ -320,6 +323,8 @@ BEGIN DROP ROLE sysadmin; DROP OWNED BY bbf_role_admin; DROP ROLE bbf_role_admin; + DROP OWNED BY securityadmin; + DROP ROLE securityadmin; END $$; @@ -365,7 +370,8 @@ CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.credential_id END AS INT) AS cr CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.owning_principal_id END AS INT) AS owning_principal_id, CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.is_fixed_role END AS sys.BIT) AS is_fixed_role FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname -WHERE (pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER') +WHERE (pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER') + OR pg_has_role(suser_id(), 'securityadmin'::TEXT, 'MEMBER') OR Ext.orig_loginname = suser_name() OR Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default OR Ext.type = 'R') @@ -501,8 +507,8 @@ CAST(Ext.orig_loginname AS sys.nvarchar(128)) AS name, CAST('SERVER ROLE' AS sys.nvarchar(128)) AS type, CAST ('GRANT OR DENY' as sys.nvarchar(128)) as usage FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname -WHERE Ext.type = 'R' AND -(pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER')); +WHERE Ext.type = 'R' +AND bbf_is_member_of_role_nosuper(sys.suser_id(), Base.oid); GRANT SELECT ON sys.login_token TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 9e652f4682..b7d5178e07 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -4530,6 +4530,10 @@ $$ $$ LANGUAGE SQL STRICT STABLE PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.bbf_is_member_of_role_nosuper(OID, OID) +RETURNS BOOLEAN AS 'babelfishpg_tsql', 'bbf_is_member_of_role_nosuper' +LANGUAGE C STABLE STRICT PARALLEL SAFE; + CREATE OR REPLACE FUNCTION sys.replace (input_string sys.VARCHAR, pattern sys.VARCHAR, replacement sys.VARCHAR) RETURNS sys.VARCHAR AS $BODY$ diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.3.0--4.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.3.0--4.4.0.sql index 51b0202cdc..36ead4234a 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.3.0--4.4.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--4.3.0--4.4.0.sql @@ -70,6 +70,211 @@ EXCEPTION WHEN OTHERS THEN END; $$; +DO +LANGUAGE plpgsql +$$ +DECLARE securityadmin TEXT; +BEGIN + IF EXISTS ( + SELECT FROM pg_catalog.pg_roles + WHERE rolname = 'securityadmin') + THEN + RAISE EXCEPTION 'Role "securityadmin" already exists.'; + ELSE + EXECUTE format('CREATE ROLE securityadmin CREATEROLE INHERIT PASSWORD NULL'); + EXECUTE format('GRANT securityadmin TO bbf_role_admin WITH ADMIN TRUE'); + CALL sys.babel_initialize_logins('securityadmin'); + END IF; +END; +$$; + +CREATE OR REPLACE FUNCTION sys.bbf_is_member_of_role_nosuper(OID, OID) +RETURNS BOOLEAN AS 'babelfishpg_tsql', 'bbf_is_member_of_role_nosuper' +LANGUAGE C STABLE STRICT PARALLEL SAFE; + +-- SERVER_PRINCIPALS +CREATE OR REPLACE VIEW sys.server_principals +AS SELECT +CAST(Ext.orig_loginname AS sys.SYSNAME) AS name, +CAST(Base.oid As INT) AS principal_id, +CAST(CAST(Base.oid as INT) as sys.varbinary(85)) AS sid, +CAST(Ext.type AS CHAR(1)) as type, +CAST( + CASE + WHEN Ext.type = 'S' THEN 'SQL_LOGIN' + WHEN Ext.type = 'R' THEN 'SERVER_ROLE' + WHEN Ext.type = 'U' THEN 'WINDOWS_LOGIN' + ELSE NULL + END + AS NVARCHAR(60)) AS type_desc, +CAST(Ext.is_disabled AS INT) AS is_disabled, +CAST(Ext.create_date AS SYS.DATETIME) AS create_date, +CAST(Ext.modify_date AS SYS.DATETIME) AS modify_date, +CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.default_database_name END AS SYS.SYSNAME) AS default_database_name, +CAST(Ext.default_language_name AS SYS.SYSNAME) AS default_language_name, +CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.credential_id END AS INT) AS credential_id, +CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.owning_principal_id END AS INT) AS owning_principal_id, +CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.is_fixed_role END AS sys.BIT) AS is_fixed_role +FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname +WHERE (pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER') + OR pg_has_role(suser_id(), 'securityadmin'::TEXT, 'MEMBER') + OR Ext.orig_loginname = suser_name() + OR Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default + OR Ext.type = 'R') + AND Ext.type != 'Z' +UNION ALL +SELECT +CAST('public' AS SYS.SYSNAME) AS name, +CAST(-1 AS INT) AS principal_id, +CAST(CAST(0 as INT) as sys.varbinary(85)) AS sid, +CAST('R' AS CHAR(1)) as type, +CAST('SERVER_ROLE' AS NVARCHAR(60)) AS type_desc, +CAST(0 AS INT) AS is_disabled, +CAST(NULL AS SYS.DATETIME) AS create_date, +CAST(NULL AS SYS.DATETIME) AS modify_date, +CAST(NULL AS SYS.SYSNAME) AS default_database_name, +CAST(NULL AS SYS.SYSNAME) AS default_language_name, +CAST(NULL AS INT) AS credential_id, +CAST(1 AS INT) AS owning_principal_id, +CAST(0 AS sys.BIT) AS is_fixed_role; + +GRANT SELECT ON sys.server_principals TO PUBLIC; + +-- login_token +CREATE OR REPLACE VIEW sys.login_token +AS SELECT +CAST(Base.oid As INT) AS principal_id, +CAST(CAST(Base.oid as INT) as sys.varbinary(85)) AS sid, +CAST(Ext.orig_loginname AS sys.nvarchar(128)) AS name, +CAST(CASE +WHEN Ext.type = 'U' THEN 'WINDOWS LOGIN' +ELSE 'SQL LOGIN' END AS SYS.NVARCHAR(128)) AS TYPE, +CAST('GRANT OR DENY' as sys.nvarchar(128)) as usage +FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname +WHERE Ext.orig_loginname = sys.suser_name() +AND Ext.type in ('S','U') +UNION ALL +SELECT +CAST(Base.oid As INT) AS principal_id, +CAST(CAST(Base.oid as INT) as sys.varbinary(85)) AS sid, +CAST(Ext.orig_loginname AS sys.nvarchar(128)) AS name, +CAST('SERVER ROLE' AS sys.nvarchar(128)) AS type, +CAST ('GRANT OR DENY' as sys.nvarchar(128)) as usage +FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname +WHERE Ext.type = 'R' +AND bbf_is_member_of_role_nosuper(sys.suser_id(), Base.oid); + +GRANT SELECT ON sys.login_token TO PUBLIC; + +CREATE OR REPLACE FUNCTION is_srvrolemember(role sys.SYSNAME, login sys.SYSNAME DEFAULT suser_name()) +RETURNS INTEGER AS +$$ +DECLARE has_role BOOLEAN; +DECLARE login_valid BOOLEAN; +BEGIN + role := TRIM(trailing from LOWER(role)); + login := TRIM(trailing from LOWER(login)); + + login_valid = (login = suser_name() COLLATE sys.database_default) OR + (EXISTS (SELECT name + FROM sys.server_principals + WHERE + LOWER(name) = login COLLATE sys.database_default + AND type = 'S')); + + IF NOT login_valid THEN + RETURN NULL; + + ELSIF role = 'public' COLLATE sys.database_default THEN + RETURN 1; + + ELSIF role = 'sysadmin' COLLATE sys.database_default OR role = 'securityadmin' COLLATE sys.database_default THEN + has_role = (pg_has_role(login::TEXT, role::TEXT, 'MEMBER') OR pg_has_role(login::TEXT, 'sysadmin'::TEXT, 'MEMBER')); + IF has_role THEN + RETURN 1; + ELSE + RETURN 0; + END IF; + + ELSIF role COLLATE sys.database_default IN ( + 'serveradmin', + 'setupadmin', + 'processadmin', + 'dbcreator', + 'diskadmin', + 'bulkadmin') THEN + RETURN 0; + + ELSE + RETURN NULL; + END IF; + + EXCEPTION WHEN OTHERS THEN + RETURN NULL; +END; +$$ LANGUAGE plpgsql STABLE; + +-- SYSLOGINS +CREATE OR REPLACE VIEW sys.syslogins +AS SELECT +Base.sid AS sid, +CAST(9 AS SYS.TINYINT) AS status, +Base.create_date AS createdate, +Base.modify_date AS updatedate, +Base.create_date AS accdate, +CAST(0 AS INT) AS totcpu, +CAST(0 AS INT) AS totio, +CAST(0 AS INT) AS spacelimit, +CAST(0 AS INT) AS timelimit, +CAST(0 AS INT) AS resultlimit, +Base.name AS name, +Base.default_database_name AS dbname, +Base.default_language_name AS default_language_name, +CAST(Base.name AS SYS.NVARCHAR(128)) AS loginname, +CAST(NULL AS SYS.NVARCHAR(128)) AS password, +CAST(0 AS INT) AS denylogin, +CAST(1 AS INT) AS hasaccess, +CAST( + CASE + WHEN Base.type_desc = 'WINDOWS_LOGIN' OR Base.type_desc = 'WINDOWS_GROUP' THEN 1 + ELSE 0 + END +AS INT) AS isntname, +CAST( + CASE + WHEN Base.type_desc = 'WINDOWS_GROUP' THEN 1 + ELSE 0 + END + AS INT) AS isntgroup, +CAST( + CASE + WHEN Base.type_desc = 'WINDOWS_LOGIN' THEN 1 + ELSE 0 + END +AS INT) AS isntuser, +CAST( + CASE + WHEN is_srvrolemember('sysadmin', Base.name) = 1 THEN 1 + ELSE 0 + END +AS INT) AS sysadmin, +CAST( + CASE + WHEN is_srvrolemember('securityadmin', Base.name) = 1 THEN 1 + ELSE 0 + END +AS INT) AS securityadmin, +CAST(0 AS INT) AS serveradmin, +CAST(0 AS INT) AS setupadmin, +CAST(0 AS INT) AS processadmin, +CAST(0 AS INT) AS diskadmin, +CAST(0 AS INT) AS dbcreator, +CAST(0 AS INT) AS bulkadmin +FROM sys.server_principals AS Base +WHERE Base.type in ('S', 'U'); + +GRANT SELECT ON sys.syslogins TO PUBLIC; + CREATE OR REPLACE VIEW sys.configurations AS SELECT configuration_id, @@ -136,6 +341,7 @@ SELECT c.value_in_use AS value, END AS status FROM sys.configurations c LEFT JOIN sys.babelfish_configurations b ON c.configuration_id = b.configuration_id; GRANT SELECT ON sys.sysconfigures TO PUBLIC; + -- Assigning dbo role to the db_owner login DO $$ DECLARE @@ -1707,56 +1913,6 @@ FROM pg_catalog.pg_class t1 JOIN information_schema.table_privileges t4 ON t1.relname = t4.table_name WHERE t4.privilege_type = 'DELETE'; -CREATE OR REPLACE FUNCTION is_srvrolemember(role sys.SYSNAME, login sys.SYSNAME DEFAULT suser_name()) -RETURNS INTEGER AS -$$ -DECLARE has_role BOOLEAN; -DECLARE login_valid BOOLEAN; -BEGIN - role := TRIM(trailing from LOWER(role)); - login := TRIM(trailing from LOWER(login)); - - login_valid = (login = suser_name() COLLATE sys.database_default) OR - (EXISTS (SELECT name - FROM sys.server_principals - WHERE - LOWER(name) = login COLLATE sys.database_default - AND type = 'S')); - - IF NOT login_valid THEN - RETURN NULL; - - ELSIF role = 'public' COLLATE sys.database_default THEN - RETURN 1; - - ELSIF role = 'sysadmin' COLLATE sys.database_default THEN - has_role = pg_has_role(login::TEXT, role::TEXT, 'MEMBER'); - IF has_role THEN - RETURN 1; - ELSE - RETURN 0; - END IF; - - ELSIF role COLLATE sys.database_default IN ( - 'serveradmin', - 'securityadmin', - 'setupadmin', - 'securityadmin', - 'processadmin', - 'dbcreator', - 'diskadmin', - 'bulkadmin') THEN - RETURN 0; - - ELSE - RETURN NULL; - END IF; - - EXCEPTION WHEN OTHERS THEN - RETURN NULL; -END; -$$ LANGUAGE plpgsql STABLE; - CREATE OR REPLACE PROCEDURE sys.sp_helpuser("@name_in_db" sys.SYSNAME = NULL) AS $$ BEGIN diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c index b221343d30..55e29044ea 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -2058,3 +2058,24 @@ tsql_index_nulls_order(List *indexParams, const char *accessMethod) } } } + +static void +check_server_role_and_throw_if_unsupported (const char *serverrole, int position, core_yyscan_t yyscanner) +{ + if (strcmp(serverrole, "serveradmin") == 0 + || strcmp(serverrole, "setupadmin") == 0 + || strcmp(serverrole, "processadmin") == 0 + || strcmp(serverrole, "diskadmin") == 0 + || strcmp(serverrole, "bulkadmin") == 0) + { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Fixed server role '%s' is currently not supported in Babelfish", serverrole), + parser_errposition(position))); + } + else if (!IS_ROLENAME_SYSADMIN(serverrole) && !IS_ROLENAME_SECURITYADMIN(serverrole)) + { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Only fixed server role is supported in ALTER SERVER ROLE statement"), + parser_errposition(position))); + } +} diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h index 868cf6762c..10495fc466 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h @@ -14,6 +14,7 @@ #include "src/backend_parser/gramparse.h" #include "src/pltsql_instr.h" +#include "src/catalog.h" #include "src/multidb.h" #include "src/tsql_for/tsql_for.h" @@ -92,3 +93,4 @@ static Node *tsql_update_output_into_cte_transformation(WithClause *opt_with_cla static List *get_transformed_output_list(List *tsql_output_clause); static bool returning_list_has_column_name(List *existing_colnames, char *current_colname); static void tsql_index_nulls_order(List *indexParams, const char *accessMethod); +static void check_server_role_and_throw_if_unsupported(const char* serverrole, int position, core_yyscan_t yyscanner); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 8c96005ef7..a0170ceb6d 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -3127,12 +3127,9 @@ tsql_alter_server_role: { GrantRoleStmt *n = makeNode(GrantRoleStmt); AccessPriv *ap = makeNode(AccessPriv); - - if (0 != strcmp($4, "sysadmin")) - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("only sysadmin role is supported in ALTER SERVER ROLE statement"), - parser_errposition(@4))); + check_server_role_and_throw_if_unsupported($4, @4, yyscanner); + ap->priv_name = $4; n->is_grant = true; n->granted_roles = list_make1(ap); @@ -3145,11 +3142,8 @@ tsql_alter_server_role: { GrantRoleStmt *n = makeNode(GrantRoleStmt); AccessPriv *ap = makeNode(AccessPriv); - - if (0 != strcmp($4, "sysadmin")) - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("only sysadmin role is supported in ALTER SERVER ROLE statement"), - parser_errposition(@4))); + + check_server_role_and_throw_if_unsupported($4, @4, yyscanner); ap->priv_name = $4; n->is_grant = false; diff --git a/contrib/babelfishpg_tsql/src/catalog.h b/contrib/babelfishpg_tsql/src/catalog.h index ff0248c9fb..05e3b1d44b 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -313,6 +313,8 @@ typedef FormData_bbf_function_ext *Form_bbf_function_ext; #define Anum_bbf_schema_perms_grantor 8 #define PUBLIC_ROLE_NAME "public" +#define BABELFISH_SECURITYADMIN "securityadmin" +#define BABELFISH_SYSADMIN "sysadmin" #define PERMISSIONS_FOR_ALL_OBJECTS_IN_SCHEMA "ALL" #define ALL_PERMISSIONS_ON_RELATION 47 /* last 6 bits as 101111 represents ALL privileges on a relation. */ #define ALL_PERMISSIONS_ON_FUNCTION 128 /* last 8 bits as 10000000 represents ALL privileges on a procedure/function. */ @@ -322,6 +324,16 @@ typedef FormData_bbf_function_ext *Form_bbf_function_ext; #define OBJ_FUNCTION "f" #define NUMBER_OF_PERMISSIONS 6 +/* check if rolename is sysadmin */ +#define IS_ROLENAME_SYSADMIN(rolname) \ + (strlen(rolname) == 8 && \ + strncmp(rolname, BABELFISH_SYSADMIN, 8) == 0) + +/* check if rolename is securityadmin */ +#define IS_ROLENAME_SECURITYADMIN(rolname) \ + (strlen(rolname) == 13 && \ + strncmp(rolname, BABELFISH_SECURITYADMIN, 13) == 0) + extern int permissions[]; extern Oid bbf_schema_perms_oid; diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index 7e0750eef3..ad6ca1fe54 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -22,6 +22,7 @@ #include "catalog.h" #include "dbcmds.h" +#include "rolecmds.h" #include "pl_explain.h" #include "pltsql.h" #include "rolecmds.h" @@ -3015,11 +3016,12 @@ exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *stmt) /* * If the login is not the db owner or the login is not the member of - * sysadmin, then it doesn't have the permission to GRANT/REVOKE. + * sysadmin or securityadmin, then it doesn't have the permission to GRANT/REVOKE. */ login_is_db_owner = 0 == strncmp(login, get_owner_of_db(dbname), NAMEDATALEN); datdba = get_role_oid("sysadmin", false); - if (!is_member_of_role(GetSessionUserId(), datdba) && !login_is_db_owner) + if (!is_member_of_role(GetSessionUserId(), datdba) && !login_is_db_owner + && !is_member_of_role(GetSessionUserId(), get_securityadmin_oid())) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Grantor does not have GRANT permission."))); diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 8c019dae19..c99179171f 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -2981,7 +2981,12 @@ bbf_ProcessUtility(PlannedStmt *pstmt, if (islogin) { - if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) + /* + * Check if the current login has privileges to create + * login. + */ + if (!has_privs_of_role(GetSessionUserId(), get_sysadmin_oid()) && + !has_privs_of_role(GetSessionUserId(), get_securityadmin_oid())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Current login %s does not have permission to create new login", @@ -3185,8 +3190,12 @@ bbf_ProcessUtility(PlannedStmt *pstmt, char *temp_login_name = NULL; Oid save_userid; int save_sec_context; + Oid securityadm_oid; + Oid role_oid; - datdba = get_role_oid("sysadmin", false); + datdba = get_sysadmin_oid(); + securityadm_oid = get_securityadmin_oid(); + role_oid = get_role_oid(stmt->role->rolename, true); /* * Check if the current login has privileges to alter @@ -3198,7 +3207,8 @@ bbf_ProcessUtility(PlannedStmt *pstmt, if (strcmp(defel->defname, "password") == 0) { - if (get_role_oid(stmt->role->rolename, true) != GetSessionUserId() && !is_member_of_role(GetSessionUserId(), datdba)) + if (role_oid != GetSessionUserId() && (!is_member_of_role(GetSessionUserId(), datdba) + && (!is_member_of_role(GetSessionUserId(), securityadm_oid) || is_member_of_role(role_oid, datdba)))) ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Cannot alter the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); @@ -3233,14 +3243,21 @@ bbf_ProcessUtility(PlannedStmt *pstmt, stmt->role->rolename = temp_login_name; } - if (!has_privs_of_role(GetSessionUserId(), datdba) && !has_password) - ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Cannot alter the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); + role_oid = get_role_oid(stmt->role->rolename, true); - if (get_role_oid(stmt->role->rolename, true) == InvalidOid) + /* + * Check if login is valid and the current login + * has privileges to alter login. + */ + if (role_oid == InvalidOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); + if (!has_privs_of_role(GetSessionUserId(), datdba) && !has_password && + (!has_privs_of_role(GetSessionUserId(), securityadm_oid) || is_member_of_role(role_oid, datdba))) + ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot alter the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); + /* * We have performed all the permissions checks. * Set current user to bbf_role_admin for alter permissions. @@ -3378,6 +3395,9 @@ bbf_ProcessUtility(PlannedStmt *pstmt, char *db_name; Oid save_userid; int save_sec_context; + Oid securityadmin_oid; + + securityadmin_oid = get_securityadmin_oid(); /* Check if roles are users that need role name mapping */ if (stmt->roles != NIL) @@ -3553,7 +3573,12 @@ bbf_ProcessUtility(PlannedStmt *pstmt, else other = true; - if (drop_login && is_login(roleform->oid) && !has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))){ + /* + * Check if the current login has privileges to drop + * login. + */ + if (drop_login && is_login(roleform->oid) && !has_privs_of_role(GetSessionUserId(), get_sysadmin_oid()) + && !has_privs_of_role(GetSessionUserId(), securityadmin_oid)){ ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", role_name))); @@ -3573,9 +3598,8 @@ bbf_ProcessUtility(PlannedStmt *pstmt, { int role_oid = get_role_oid(role_name, true); - if (!OidIsValid(role_oid) || - !is_member_of_role(GetSessionUserId(), get_sysadmin_oid()) || - role_oid == get_bbf_role_admin_oid()) + if (!OidIsValid(role_oid) || role_oid == get_bbf_role_admin_oid() + || role_oid == securityadmin_oid || role_oid == get_sysadmin_oid()) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", role_name))); @@ -3769,13 +3793,46 @@ bbf_ProcessUtility(PlannedStmt *pstmt, { StringInfoData query; RoleSpec *spec; + RoleSpec *rolspec; + Oid grantee_oid; + check_alter_server_stmt(grant_role); spec = (RoleSpec *) linitial(grant_role->grantee_roles); + rolspec = (RoleSpec *) linitial(grant_role->granted_roles); + grantee_oid = get_role_oid(spec->rolename, false); initStringInfo(&query); - if (grant_role->is_grant) - appendStringInfo(&query, "ALTER ROLE dummy WITH createrole createdb; "); + + /* If sysadmin, provide attribute for role and database priv */ + if (IS_ROLENAME_SYSADMIN(rolspec->rolename)) + { + if (grant_role->is_grant) + appendStringInfo(&query, "ALTER ROLE dummy WITH createrole createdb; "); + + /* If grantee role is member of securityadmin then only revoke createdb */ + else if (has_privs_of_role(grantee_oid, get_securityadmin_oid())) + appendStringInfo(&query, "ALTER ROLE dummy WITH nocreatedb; "); + else + appendStringInfo(&query, "ALTER ROLE dummy WITH nocreaterole nocreatedb; "); + } + + /* If securityadmin, provide attribute for role priv */ + else if (IS_ROLENAME_SECURITYADMIN(rolspec->rolename)) + { + if (grant_role->is_grant) + appendStringInfo(&query, "ALTER ROLE dummy WITH createrole; "); + + /* If grantee role is member of sysadmin then don't revoke createrole */ + else if (!has_privs_of_role(grantee_oid, get_sysadmin_oid())) + appendStringInfo(&query, "ALTER ROLE dummy WITH nocreaterole; "); + } + + /* Otherwise, throw error */ else - appendStringInfo(&query, "ALTER ROLE dummy WITH nocreaterole nocreatedb; "); + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("\"%s\" is not a supported fixed server role.", rolspec->rolename))); + } /* * Set to bbf_role_admin to grant the role @@ -3792,7 +3849,8 @@ bbf_ProcessUtility(PlannedStmt *pstmt, else standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); - exec_alter_role_cmd(query.data, spec); + if (query.len) + exec_alter_role_cmd(query.data, spec); } PG_FINALLY(); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 6d95de49f8..0233975bd1 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -2997,6 +2997,8 @@ sp_addlinkedsrvlogin_internal(PG_FUNCTION_ARGS) char *locallogin = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(2)); char *username = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(3)); char *password = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(4)); + Oid save_userid; + int save_sec_context; StringInfoData query; @@ -3023,6 +3025,16 @@ sp_addlinkedsrvlogin_internal(PG_FUNCTION_ARGS) initStringInfo(&query); + /* + * check privileges for login + * allow if has privileges of sysadmin or securityadmin. + */ + if (!has_privs_of_role(GetSessionUserId(), get_sysadmin_oid()) && + !has_privs_of_role(GetSessionUserId(), get_securityadmin_oid())) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("User does not have permission to perform this action."))); + /* * We prepare the following query to create a user mapping. This will be * executed using ProcessUtility(): @@ -3058,8 +3070,22 @@ sp_addlinkedsrvlogin_internal(PG_FUNCTION_ARGS) appendStringInfoString(&query, ")"); } + /* + * We have performed all the permissions checks. + * Set current user to bbf_role_admin for mapping permissions. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(get_bbf_role_admin_oid(), save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - exec_utility_cmd_helper(query.data); + PG_TRY(); + { + exec_utility_cmd_helper(query.data); + } + PG_FINALLY(); + { + SetUserIdAndSecContext(save_userid, save_sec_context); + } + PG_END_TRY(); if (servername) pfree(servername); @@ -3083,6 +3109,8 @@ sp_droplinkedsrvlogin_internal(PG_FUNCTION_ARGS) { char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); char *locallogin = PG_ARGISNULL(1) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(1)); + Oid save_userid; + int save_sec_context; StringInfoData query; @@ -3103,33 +3131,59 @@ sp_droplinkedsrvlogin_internal(PG_FUNCTION_ARGS) remove_trailing_spaces(servername); + /* + * check privileges for login + * allow if has privileges of sysadmin or securityadmin. + */ + if (!has_privs_of_role(GetSessionUserId(), get_sysadmin_oid()) && + !has_privs_of_role(GetSessionUserId(), get_securityadmin_oid())) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("User does not have permission to perform this action."))); + /* Check if servername is valid */ get_foreign_server_oid(servername, false); initStringInfo(&query); /* - * We prepare the following queries to drop a linked server login. This will - * be executed using ProcessUtility(): - * - * DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER @SERVERNAME - * DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER @SERVERNAME - * - * Linked logins were first implemented as PG USER MAPPINGs for the CURRENT_USER which - * was not entirely correct because T-SQL linked logins are not user or login specific. - * To address this we now create user mapping for the PG PUBLIC role internally. - * - * To ensure sp_droplinkedsrvlogin works in accordance with both the older and newer - * implementation of linked logins, we try to drop USER MAPPINGs for both the CURRENT_USER - * and PUBLIC PG roles. - */ - appendStringInfo(&query, "DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER \"%s\"", servername); - exec_utility_cmd_helper(query.data); + * We have performed all the permissions checks. + * Set current user to bbf_role_admin for mapping permissions. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(get_bbf_role_admin_oid(), save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - resetStringInfo(&query); + PG_TRY(); + { + /* + * We prepare the following queries to drop a linked server login. This will + * be executed using ProcessUtility(): + * + * DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER @SERVERNAME + * DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER @SERVERNAME + * + * Linked logins were first implemented as PG USER MAPPINGs for the CURRENT_USER which + * was not entirely correct because T-SQL linked logins are not user or login specific. + * To address this we now create user mapping for the PG PUBLIC role internally. + * + * To ensure sp_droplinkedsrvlogin works in accordance with both the older and newer + * implementation of linked logins, we try to drop USER MAPPINGs for both the CURRENT_USER + * and PUBLIC PG roles. + */ + appendStringInfo(&query, "DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER \"%s\"", servername); + exec_utility_cmd_helper(query.data); - appendStringInfo(&query, "DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER \"%s\"", servername); - exec_utility_cmd_helper(query.data); + resetStringInfo(&query); + + appendStringInfo(&query, "DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER \"%s\"", servername); + exec_utility_cmd_helper(query.data); + } + + PG_FINALLY(); + { + SetUserIdAndSecContext(save_userid, save_sec_context); + } + PG_END_TRY(); if (locallogin) pfree(locallogin); @@ -3137,6 +3191,8 @@ sp_droplinkedsrvlogin_internal(PG_FUNCTION_ARGS) if (servername) pfree(servername); + pfree(query.data); + return (Datum) 0; } diff --git a/contrib/babelfishpg_tsql/src/rolecmds.c b/contrib/babelfishpg_tsql/src/rolecmds.c index 136a97b1a4..58b35f70e2 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.c +++ b/contrib/babelfishpg_tsql/src/rolecmds.c @@ -77,6 +77,7 @@ static void validateNetBIOS(char *netbios); static void validateFQDN(char *fqdn); static Oid bbf_admin_oid = InvalidOid; +static Oid securityadmin_oid = InvalidOid; void create_bbf_authid_login_ext(CreateRoleStmt *stmt) @@ -146,6 +147,8 @@ create_bbf_authid_login_ext(CreateRoleStmt *stmt) new_record_login_ext[LOGIN_EXT_TYPE] = CStringGetTextDatum("R"); else if (strcmp(stmt->role, "bbf_role_admin") == 0) new_record_login_ext[LOGIN_EXT_TYPE] = CStringGetTextDatum("Z"); + else if (strcmp(stmt->role, BABELFISH_SECURITYADMIN) == 0) + new_record_login_ext[LOGIN_EXT_TYPE] = CStringGetTextDatum("R"); else if (from_windows) new_record_login_ext[LOGIN_EXT_TYPE] = CStringGetTextDatum("U"); else @@ -685,6 +688,16 @@ get_bbf_role_admin_oid(void) return bbf_admin_oid; } + +/* Returns OID of securityadmin server role */ +Oid +get_securityadmin_oid(void) +{ + if (!OidIsValid(securityadmin_oid)) + securityadmin_oid = get_role_oid(BABELFISH_SECURITYADMIN, false); + return securityadmin_oid; +} + /* * Returns OID of SA of the current database. * We assume that SA is the DBA of the babelfish DB. @@ -1662,7 +1675,7 @@ bool is_alter_server_stmt(GrantRoleStmt *stmt) { /* - * is alter server role statement, if one and the only one granted role is + * is alter server role statement, if the granted role is * server role */ @@ -1670,13 +1683,10 @@ is_alter_server_stmt(GrantRoleStmt *stmt) { RoleSpec *spec = (RoleSpec *) linitial(stmt->granted_roles); - if (strcmp(spec->rolename, "sysadmin") == 0) /* only supported server - * role */ + /* only supported server roles */ + if (IS_ROLENAME_SYSADMIN(spec->rolename) || IS_ROLENAME_SECURITYADMIN(spec->rolename)) return true; } - /* has one and only one grantee */ - if (list_length(stmt->grantee_roles) != 1) - return false; return false; } @@ -1716,8 +1726,12 @@ check_alter_server_stmt(GrantRoleStmt *stmt) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("%s is not a login", grantee_name))); - /* only sysadmin role is assumed below */ - if (!has_privs_of_role(GetSessionUserId(), sysadmin)) + /* + * check if it has sysadmin privileges or + * if server role is securityadmin and it has privileges of securityadmin + */ + if (!has_privs_of_role(GetSessionUserId(), sysadmin) && ((strcmp(granted_name, BABELFISH_SECURITYADMIN) != 0) + || !has_privs_of_role(GetSessionUserId(), get_securityadmin_oid()))) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Current login %s does not have permission to alter server role", @@ -2545,3 +2559,21 @@ remove_createrole_from_logins(PG_FUNCTION_ARGS) table_close(rel, AccessShareLock); PG_RETURN_INT32(0); } + +PG_FUNCTION_INFO_V1(bbf_is_member_of_role_nosuper); +Datum +bbf_is_member_of_role_nosuper(PG_FUNCTION_ARGS) +{ + Oid member, role; + bool result; + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + + member = PG_GETARG_OID(0); + role = PG_GETARG_OID(1); + + result = is_member_of_role_nosuper(member, role); + + PG_RETURN_BOOL(result); +} diff --git a/contrib/babelfishpg_tsql/src/rolecmds.h b/contrib/babelfishpg_tsql/src/rolecmds.h index e5f9f9db5b..b1459efee5 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.h +++ b/contrib/babelfishpg_tsql/src/rolecmds.h @@ -55,6 +55,7 @@ extern void drop_bbf_roles(ObjectAccessType access, void *arg); extern bool role_is_sa(Oid roleid); extern Oid get_bbf_role_admin_oid(void); +extern Oid get_securityadmin_oid(void); extern Oid get_sa_role_oid(void); extern bool tsql_has_pgstat_permissions(Oid roleid); extern bool tsql_has_linked_srv_permissions(Oid roleid); diff --git a/test/JDBC/expected/BABEL-2403.out b/test/JDBC/expected/BABEL-2403.out index c879c5bf23..c3e19ceb06 100644 --- a/test/JDBC/expected/BABEL-2403.out +++ b/test/JDBC/expected/BABEL-2403.out @@ -81,6 +81,8 @@ name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} +name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} +text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_user_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} @@ -170,6 +172,8 @@ name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} +name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} +text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_user_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} diff --git a/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out b/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out index 5437c600c8..e09fa162bb 100644 --- a/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out +++ b/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out @@ -277,7 +277,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -3 +4 ~~END~~ @@ -288,7 +288,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -4 +5 ~~END~~ @@ -300,7 +300,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -5 +6 ~~END~~ @@ -388,7 +388,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -4 +5 ~~END~~ @@ -418,7 +418,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -3 +4 ~~END~~ @@ -489,14 +489,14 @@ ALTER SERVER ROLE db_owner ADD MEMBER dummy; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ ALTER SERVER ROLE db_owner DROP MEMBER dummy; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ CREATE LOGIN err_user WITH PASSWORD = '123'; diff --git a/test/JDBC/expected/BABEL-LOGIN-vu-verify.out b/test/JDBC/expected/BABEL-LOGIN-vu-verify.out index 22aa32d6ee..e35d0a6387 100644 --- a/test/JDBC/expected/BABEL-LOGIN-vu-verify.out +++ b/test/JDBC/expected/BABEL-LOGIN-vu-verify.out @@ -274,14 +274,14 @@ ALTER SERVER ROLE db_owner ADD MEMBER dummy; go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ ALTER SERVER ROLE db_owner DROP MEMBER dummy; go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ CREATE USER babel_login_vu_prepare_err_user; diff --git a/test/JDBC/expected/bbf_role_admin_restrictions.out b/test/JDBC/expected/bbf_role_admin_restrictions.out index ae3eef5526..113c662862 100644 --- a/test/JDBC/expected/bbf_role_admin_restrictions.out +++ b/test/JDBC/expected/bbf_role_admin_restrictions.out @@ -20,7 +20,7 @@ ALTER SERVER ROLE bbf_role_admin ADD MEMBER bbf_role_admin_restrictions_role; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ ALTER ROLE bbf_role_admin_restrictions_role ADD MEMBER bbf_role_admin; diff --git a/test/JDBC/expected/is_srvrolemember-vu-verify.out b/test/JDBC/expected/is_srvrolemember-vu-verify.out index d68cecfa6e..4955dd3fbc 100644 --- a/test/JDBC/expected/is_srvrolemember-vu-verify.out +++ b/test/JDBC/expected/is_srvrolemember-vu-verify.out @@ -122,7 +122,7 @@ SELECT is_srvrolemember('securityadmin') GO ~~START~~ int -0 +1 ~~END~~ diff --git a/test/JDBC/expected/is_srvrolemember.out b/test/JDBC/expected/is_srvrolemember.out index d68cecfa6e..4955dd3fbc 100644 --- a/test/JDBC/expected/is_srvrolemember.out +++ b/test/JDBC/expected/is_srvrolemember.out @@ -122,7 +122,7 @@ SELECT is_srvrolemember('securityadmin') GO ~~START~~ int -0 +1 ~~END~~ diff --git a/test/JDBC/expected/securityadmin_role-vu-cleanup.out b/test/JDBC/expected/securityadmin_role-vu-cleanup.out new file mode 100644 index 0000000000..fb82964f8d --- /dev/null +++ b/test/JDBC/expected/securityadmin_role-vu-cleanup.out @@ -0,0 +1,63 @@ +-- tsql +drop user securityadmin_user1 +go + +drop user no_securityadmin_user1 +go + +drop login securityadmin_login1 +go + +use securityadmin_db1 +go + +drop user no_securityadmin_user1 +go + +use master +go + +drop login no_securityadmin_login1 +go + +drop database securityadmin_db1 +go + +drop schema securityadmin_scm1 +go + +drop view securityadmin_show_role_mem +go + +drop TRIGGER securityadmin_tggr1 +go + +drop table securityadmin_tb1 +go + +drop view securityadmin_v1 +go + +drop function securityadmin_func1() +go + +drop procedure securityadmin_proc1 +go + +drop procedure securityadmin_create_login_p1 +go + +drop procedure securityadmin_alter_login_p1 +go + +drop procedure securityadmin_drop_login_p1 +go + +drop procedure securityadmin_add_mem_p1 +go + +drop procedure securityadmin_drop_mem_p1 +go + +drop role securityadmin_rol +go diff --git a/test/JDBC/expected/securityadmin_role-vu-prepare.out b/test/JDBC/expected/securityadmin_role-vu-prepare.out new file mode 100644 index 0000000000..1f96ebe37e --- /dev/null +++ b/test/JDBC/expected/securityadmin_role-vu-prepare.out @@ -0,0 +1,90 @@ +-- tsql +create login securityadmin_login1 with password = '123' +go + +create login no_securityadmin_login1 with password = '123' +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +-- tsql +create role securityadmin_rol +go + +create database securityadmin_db1 +go + +create schema securityadmin_scm1 +go + +CREATE VIEW securityadmin_show_role_mem AS +SELECT +roles.name AS RolePrincipalName +, members.name AS MemberPrincipalName +FROM sys.server_role_members AS server_role_members +INNER JOIN sys.server_principals AS roles + ON server_role_members.role_principal_id = roles.principal_id +INNER JOIN sys.server_principals AS members + ON server_role_members.member_principal_id = members.principal_id order by MemberPrincipalName; +GO + +create table securityadmin_tb1(a int) +go + +create view securityadmin_v1 as select 1; +go + +create function securityadmin_func1() returns int as begin return 1 end; +go + +create procedure securityadmin_proc1 as begin select 1; end +go + +CREATE TRIGGER securityadmin_tggr1 on securityadmin_tb1 AFTER INSERT AS BEGIN END; +go + +create procedure securityadmin_create_login_p1 as begin create login securityadmin_login_new with password ='123'; end +go + +Grant execute on securityadmin_create_login_p1 to PUBLIC; +go + +create procedure securityadmin_alter_login_p1 as begin alter login securityadmin_login_new with password ='1234'; end +go + +Grant execute on securityadmin_alter_login_p1 to PUBLIC; +go + +create procedure securityadmin_drop_login_p1 as begin drop login securityadmin_login_new; end +go + +Grant execute on securityadmin_drop_login_p1 to PUBLIC; +go + +create procedure securityadmin_add_mem_p1 as begin Alter server role securityadmin add member securityadmin_login_new; end +go + +Grant execute on securityadmin_add_mem_p1 to PUBLIC; +go + +create procedure securityadmin_drop_mem_p1 as begin Alter server role securityadmin drop member securityadmin_login_new; end +go + +Grant execute on securityadmin_drop_mem_p1 to PUBLIC; +go + +use securityadmin_db1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +use master +go diff --git a/test/JDBC/expected/securityadmin_role-vu-verify.out b/test/JDBC/expected/securityadmin_role-vu-verify.out new file mode 100644 index 0000000000..f3b35d0386 --- /dev/null +++ b/test/JDBC/expected/securityadmin_role-vu-verify.out @@ -0,0 +1,1609 @@ +-- tsql +alter login securityadmin_login1 with password='123' +go + +alter login no_securityadmin_login1 with password='123' +go + +-- make login member of securityadmin +Alter server role securityadmin add member securityadmin_login1 +go + +select * from securityadmin_show_role_mem where MemberPrincipalName like 'jdbc_user' or MemberPrincipalName like '%securityadmin_%' +go +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +securityadmin#!#securityadmin_login1 +~~END~~ + + +-- should error out +create login securityadmin with password = '123' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The Server principal 'securityadmin' already exists)~~ + + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- Case 1 - positives +-- securityadmin's login privileges +-- alter server role securityadmin should be allowed +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('securityadmin')) +go +~~START~~ +bit +1 +~~END~~ + + +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('sysadmin')) +go +~~START~~ +bit +0 +~~END~~ + + +Alter server role securityadmin add member no_securityadmin_login1 +go + +Alter server role securityadmin drop member no_securityadmin_login1 +go + +-- create login should be allowed +-- windows login +create login [babel\securityadmin_l1] from windows; +go + +-- password based login +create login securityadmin_l2 with password = '123' +go + +-- alter login should be allowed +-- password based login +alter login securityadmin_l2 with password = '123' +go + +ALTER LOGIN securityadmin_l2 WITH PASSWORD = '1234' OLD_PASSWORD = '123'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'OLD_PASSWORD' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_login_old_password to ignore)~~ + + +ALTER LOGIN securityadmin_l2 disable; +go + +ALTER LOGIN securityadmin_l2 enable; +go + +ALTER LOGIN securityadmin_l2 with default_database=securityadmin_db1; +go + +-- windows login +alter login [babel\securityadmin_l1] with PASSWORD='123' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot use parameter PASSWORD for a windows login)~~ + + +ALTER LOGIN [babel\securityadmin_l1] WITH PASSWORD = '1234' OLD_PASSWORD = '123'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'OLD_PASSWORD' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_login_old_password to ignore)~~ + + +ALTER LOGIN [babel\securityadmin_l1] disable; +go + +ALTER LOGIN [babel\securityadmin_l1] enable; +go + +ALTER LOGIN [babel\securityadmin_l1] with default_database=securityadmin_db1; +go + +-- make altering login member of securityadmin +Alter server role securityadmin add member securityadmin_l2 +go + +-- alter securityadmin member login +-- allowed +alter login securityadmin_l2 with password = '123' +go + +-- drop login should be allowed +-- password based login +drop login securityadmin_l2 +go + +-- windows login +drop login [babel\securityadmin_l1] +go + +-- grant server permissions (currently not supported) +-- few examples +GRANT CONTROL SERVER TO no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT Database' is not currently supported in Babelfish)~~ + + +GRANT ALTER ANY EVENT NOTIFICATION TO no_securityadmin_login1 WITH GRANT OPTION; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT Database' is not currently supported in Babelfish)~~ + + +GRANT ALTER ANY DATABASE TO no_securityadmin_login1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT Database' is not currently supported in Babelfish)~~ + + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql user=no_securityadmin_login1 password=123 +-- grant database permissions (only connect is supported) +-- allowed +use securityadmin_db1 +go + +-- terminate-tsql-conn user=no_securityadmin_login1 password=123 + +-- tsql user=securityadmin_login1 password=123 database=securityadmin_db1 +REVOKE CONNECT FROM no_securityadmin_user1 +go + +-- unsupported +GRANT SHOWPLAN TO no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT Database' is not currently supported in Babelfish)~~ + + +GRANT CREATE VIEW TO no_securityadmin_user1 WITH GRANT OPTION; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'GRANT Database' is not currently supported in Babelfish)~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 database=securityadmin_db1 + +-- tsql user=no_securityadmin_login1 password=123 +-- connection revoked +use securityadmin_db1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server principal "no_securityadmin_login1" is not able to access the database "securityadmin_db1" under the current security context)~~ + + +-- terminate-tsql-conn user=no_securityadmin_login1 password=123 + +-- tsql user=securityadmin_login1 password=123 database=securityadmin_db1 +-- revoke server permissions (currently not supported) +-- few examples +REVOKE CONTROL SERVER FROM no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE Database' is not currently supported in Babelfish)~~ + + +REVOKE ALTER ANY EVENT NOTIFICATION FROM no_securityadmin_login1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE Database' is not currently supported in Babelfish)~~ + + +REVOKE ALTER ANY DATABASE FROM no_securityadmin_login1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE Database' is not currently supported in Babelfish)~~ + + +-- grant database permissions (only connect is supported) +GRANT CONNECT TO no_securityadmin_user1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 database=securityadmin_db1 + +-- tsql user=no_securityadmin_login1 password=123 +use securityadmin_db1 +go + +-- Check unprivileged login should not have access +-- permission denied +EXEC sp_addlinkedsrvlogin 'Accounts', 'False' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: User does not have permission to perform this action.)~~ + + +EXEC sp_droplinkedsrvlogin 'Accounts', NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: User does not have permission to perform this action.)~~ + + +Alter server role securityadmin add member no_securityadmin_login1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login no_securityadmin_login1 does not have permission to alter server role)~~ + + +Alter server role securityadmin drop member no_securityadmin_login1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login no_securityadmin_login1 does not have permission to alter server role)~~ + + +-- only current login and fixed server roles +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals ORDER BY name +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +no_securityadmin_login1#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +public#!#R#!#SERVER_ROLE#!##!##!##!#1#!#0 +securityadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +sysadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +~~END~~ + + +-- only current login +select name, type, usage from sys.login_token order by name; +go +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +no_securityadmin_login1#!#SQL LOGIN#!#GRANT OR DENY +~~END~~ + + +-- terminate-tsql-conn user=no_securityadmin_login1 password=123 + +-- tsql user=securityadmin_login1 password=123 +-- unsupported +REVOKE SHOWPLAN FROM no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE Database' is not currently supported in Babelfish)~~ + + +REVOKE CREATE VIEW FROM no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'REVOKE Database' is not currently supported in Babelfish)~~ + + +-- System objects +-- All rows of server_prinicipals view should be visible to securityadmin login +-- limited rows should get displayed +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals +WHERE name in ('jdbc_user', 'sysadmin', 'public', 'securityadmin') ORDER BY name; +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +public#!#R#!#SERVER_ROLE#!##!##!##!#1#!#0 +securityadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +sysadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +~~END~~ + + +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals name WHERE name like '%securityadmin%' ORDER BY name; +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +no_securityadmin_login1#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +securityadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +securityadmin_login1#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +~~END~~ + + +-- current login along with current fixed role should be visible +select name, type, usage from sys.login_token order by name; +go +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +securityadmin#!#SERVER ROLE#!#GRANT OR DENY +securityadmin_login1#!#SQL LOGIN#!#GRANT OR DENY +~~END~~ + + +select name, sysadmin, securityadmin from syslogins where name like '%securityadmin%' order by name +go +~~START~~ +varchar#!#int#!#int +no_securityadmin_login1#!#0#!#0 +securityadmin_login1#!#0#!#1 +~~END~~ + + +-- should return 0 +select is_srvrolemember ('sysadmin') +go +~~START~~ +int +0 +~~END~~ + + +-- should return 1 +select is_srvrolemember ('securityadmin') +go +~~START~~ +int +1 +~~END~~ + + +select is_srvrolemember ('securityadmin', 'securityadmin_login1') +go +~~START~~ +int +1 +~~END~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- psql +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +-- Add localhost as linked server +EXEC sp_addlinkedserver @server = N'server_4229', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +EXEC sp_addlinkedserver 'Accounts' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'server_4229', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +drop database securityadmin_db1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +EXEC sp_addlinkedsrvlogin 'Accounts', 'False' +GO + +EXEC sp_droplinkedsrvlogin 'Accounts', NULL +GO + +-- inside procedure +exec securityadmin_create_login_p1 +go + +exec securityadmin_alter_login_p1 +go + +exec securityadmin_add_mem_p1 +go + +exec securityadmin_drop_mem_p1 +go + +exec securityadmin_drop_login_p1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- login is member of both securityadmin as well as sysadmin +drop user securityadmin_user1 +go + +Alter server role sysadmin add member securityadmin_login1 +go + +create database securityadmin_db1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- it should be able to connect to the database +use securityadmin_db1 +go + +-- it should be dbo +select current_user +go +~~START~~ +varchar +dbo +~~END~~ + + +-- both attribute should be true +select rolname, rolcreaterole, rolcreatedb from pg_roles where rolname = 'securityadmin_login1' +go +~~START~~ +varchar#!#bit#!#bit +securityadmin_login1#!#1#!#1 +~~END~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- only member of securityadmin +alter server role sysadmin drop member securityadmin_login1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 + +-- only rolcreaterole attribute should be true +select rolname, rolcreaterole, rolcreatedb from pg_roles where rolname = 'securityadmin_login1' +go +~~START~~ +varchar#!#bit#!#bit +securityadmin_login1#!#1#!#0 +~~END~~ + + +-- should be able to create/drop login +create login test_securityadmin_l1 with password ='123' +go + +drop login test_securityadmin_l1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- only member of sysadmin +drop user securityadmin_user1 +go + +alter server role sysadmin add member securityadmin_login1 +go + +alter server role securityadmin drop member securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 + +-- both attribute should be true +select rolname, rolcreaterole, rolcreatedb from pg_roles where rolname = 'securityadmin_login1' +go +~~START~~ +varchar#!#bit#!#bit +securityadmin_login1#!#1#!#1 +~~END~~ + + +-- should be able to create/drop login +create login test_securityadmin_l1 with password ='123' +go + +drop login test_securityadmin_l1 +go + +-- should return 1 +select is_srvrolemember ('sysadmin') +go +~~START~~ +int +1 +~~END~~ + + +-- should return 1 +select is_srvrolemember ('securityadmin') +go +~~START~~ +int +1 +~~END~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- make it member of securityadmin only +alter server role sysadmin drop member securityadmin_login1 +go + +alter server role securityadmin add member securityadmin_login1 +go + +drop user no_securityadmin_user1 +go + +alter server role sysadmin add member no_securityadmin_login1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- Case 2 - negatives +-- alter server role sysadmin should give permission denied +Alter server role sysadmin add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login securityadmin_login1 does not have permission to alter server role)~~ + + +-- alter server role securityadmin add member db roles should error out +Alter server role securityadmin add member guest +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: role "guest" does not exist)~~ + + +-- alter sysadmin login should give permission denied +-- login which is altered is member of sysadmin +Alter login no_securityadmin_login1 with password ='123' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot alter the login 'no_securityadmin_login1', because it does not exist or you do not have permission.)~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- make member of securityadmin as well +alter server role securityadmin add member no_securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- login which is altered is member of sysadmin and securityadmin both +-- permission denied +Alter login no_securityadmin_login1 with password ='123' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot alter the login 'no_securityadmin_login1', because it does not exist or you do not have permission.)~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +alter server role securityadmin drop member no_securityadmin_login1 +go + +alter server role sysadmin drop member no_securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +create role dummy_role +go + +drop database securityadmin_db1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- should error out +Alter server role securityadmin add member dummy_role +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: role "dummy_role" does not exist)~~ + + +-- create database permission denied +create database perm_denied_db +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied to create database)~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +drop role dummy_role +go + +create database securityadmin_db1 +go + +use securityadmin_db1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- alter database permission denied +alter database securityadmin_db1 modify name = rename_db_database1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: User does not have permission to rename the database 'securityadmin_db1', the database does not exist, or the database is not in a state that allows access checks.)~~ + + +alter authorization on database::securityadmin_db1 to no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'no_securityadmin_login1', because it does not exist or you do not have permission.)~~ + + +-- drop database permission denied +drop database securityadmin_db1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of database securityadmin_db1)~~ + + +-- securityadmin login's mapped user should not have any priv +select current_user, db_name() +go +~~START~~ +varchar#!#nvarchar +securityadmin_user1#!#master +~~END~~ + + +select suser_name() +go +~~START~~ +nvarchar +securityadmin_login1 +~~END~~ + + +-- allowed +create login securityadmin_l2 with password = '123' +go + +-- create objects/user permission denied +create user securityadmin_l2 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: User does not have permission to perform this action.)~~ + + +create role securityadmin_role1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: User does not have permission to perform this action.)~~ + + +create schema perm_denied_scm +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for database jdbc_testdb)~~ + + +create view perm_denied_v1 as select 1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +create table perm_denied_tb1 (a int); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +select 1 into perm_denied_tb2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +create function perm_denied_func1() returns int as begin return 1 end; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +create procedure perm_denied_proc1 as begin select 1; end +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +create type perm_denied_typ1 from int; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +create index perm_denied_index1 on securityadmin_tb1(a); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table securityadmin_tb1)~~ + + +CREATE FUNCTION perm_denied_func1() RETURNS TABLE AS RETURN ( SELECT 1 AS Value); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for schema master_dbo)~~ + + +-- DMLS on object permission denied +Alter user no_securityadmin_user1 with DEFAULT_SCHEMA=securityadmin_scm1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current user does not have privileges to change schema)~~ + + +Alter role securityadmin_rol add member no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login securityadmin_login1 does not have permission to alter role master_securityadmin_rol)~~ + + +Alter role securityadmin_rol drop member no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login securityadmin_login1 does not have permission to alter role master_securityadmin_rol)~~ + + +Alter table securityadmin_tb1 add b int +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table securityadmin_tb1)~~ + + +Insert into securityadmin_tb1 values (1) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +UPDATE securityadmin_tb1 SET a = 2 where a = 1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +DELETE FROM securityadmin_tb1 WHERE a = 1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +TRUNCATE TABLE securityadmin_tb1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +select * from securityadmin_tb1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +select * from securityadmin_v1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view securityadmin_v1)~~ + + +select securityadmin_func1() +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_func1)~~ + + +exec securityadmin_proc1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure securityadmin_proc1)~~ + + +Enable trigger securityadmin_tggr1 on securityadmin_tb1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table securityadmin_tb1)~~ + + +Disable trigger securityadmin_tggr1 on securityadmin_tb1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table securityadmin_tb1)~~ + + +-- grant on objects permission denied +Grant select on securityadmin_tb1 to no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +Grant update on securityadmin_v1 to no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + + +Grant update on securityadmin_v1 to no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + + +Grant exec on securityadmin_func1 to no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_func1)~~ + + +Grant exec on securityadmin_proc1 to no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_proc1)~~ + + +-- Revoke on objects permission denied +Revoke select on securityadmin_tb1 from no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_tb1)~~ + + +Revoke update on securityadmin_v1 from no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + + +Revoke update on securityadmin_v1 from no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + + +Revoke exec on securityadmin_func1 from no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_func1)~~ + + +Revoke exec on securityadmin_proc1 from no_securityadmin_user1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_proc1)~~ + + +-- grant on schema +-- permission denied +grant select on securityadmin_v1 to no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + +grant select on dbo.securityadmin_v1 to no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + +grant execute on securityadmin_proc1 to no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_proc1)~~ + +grant execute on dbo.securityadmin_proc1 to no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_proc1)~~ + + +-- revoke on schema +-- permission denied +revoke select on securityadmin_v1 from no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + +revoke select on dbo.securityadmin_v1 from no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table securityadmin_v1)~~ + +revoke execute on securityadmin_proc1 from no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_proc1)~~ + +revoke execute on dbo.securityadmin_proc1 from no_securityadmin_user1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function securityadmin_proc1)~~ + + +-- drop object permission denied +drop user securityadmin_l2 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot drop the user 'securityadmin_l2', because it does not exist or you do not have permission.)~~ + + +drop role securityadmin_rol +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot drop the role 'securityadmin_rol', because it does not exist or you do not have permission.)~~ + + +drop schema securityadmin_scm1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of schema master_securityadmin_scm1)~~ + + +drop view securityadmin_show_role_mem +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of view securityadmin_show_role_mem)~~ + + +drop TRIGGER securityadmin_tggr1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of relation securityadmin_tb1)~~ + + +drop table securityadmin_tb1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table securityadmin_tb1)~~ + + +drop view securityadmin_v1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of view securityadmin_v1)~~ + + +drop function securityadmin_func1() +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of function securityadmin_func1)~~ + + +drop procedure securityadmin_proc1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of procedure securityadmin_proc1)~~ + + +-- allowed drop login +drop login securityadmin_l2 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + + +-- tsql database=securityadmin_db1 +-- securityadmin login should not get mapped to dbo if no user exist, it should disconnect +drop user securityadmin_user1 +go + +-- terminate-tsql-conn database=securityadmin_db1 + +-- tsql user=securityadmin_login1 password=123 +-- it should disconnect +use securityadmin_db1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server principal "securityadmin_login1" is not able to access the database "securityadmin_db1" under the current security context)~~ + + +-- tsql +-- Case 3 - alter server role other than securityadmin and sysadmin should give unsupported +Alter server role false_role add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ + + +Alter server role serveradmin add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'serveradmin' is currently not supported in Babelfish)~~ + + +Alter server role setupadmin add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'setupadmin' is currently not supported in Babelfish)~~ + + +Alter server role processadmin add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'processadmin' is currently not supported in Babelfish)~~ + + +Alter server role diskadmin add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'diskadmin' is currently not supported in Babelfish)~~ + + +Alter server role bulkadmin add member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'bulkadmin' is currently not supported in Babelfish)~~ + + +Alter server role false_role drop member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ + + +Alter server role serveradmin drop member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'serveradmin' is currently not supported in Babelfish)~~ + + +Alter server role setupadmin drop member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'setupadmin' is currently not supported in Babelfish)~~ + + +Alter server role processadmin drop member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'processadmin' is currently not supported in Babelfish)~~ + + +Alter server role diskadmin drop member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'diskadmin' is currently not supported in Babelfish)~~ + + +Alter server role bulkadmin drop member no_securityadmin_login1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Fixed server role 'bulkadmin' is currently not supported in Babelfish)~~ + + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- Case 4 - check unintended/unauthorized use of securityadmin +CREATE LOGIN securityadmin_restrict_new_login WITH password = '12345678'; +go + +ALTER SERVER ROLE sysadmin ADD MEMBER securityadmin_restrict_new_login; +GO + +select * from securityadmin_show_role_mem where MemberPrincipalName like 'jdbc_user' or MemberPrincipalName like '%securityadmin_%' +go +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +securityadmin#!#securityadmin_login1 +sysadmin#!#securityadmin_restrict_new_login +~~END~~ + + +-- terminate-tsql-conn + +-- tsql user=securityadmin_restrict_new_login password=12345678 +select * from securityadmin_show_role_mem where MemberPrincipalName like 'jdbc_user' or MemberPrincipalName like '%securityadmin_%' +go +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +securityadmin#!#securityadmin_login1 +sysadmin#!#securityadmin_restrict_new_login +~~END~~ + + +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('securityadmin')) +go +~~START~~ +bit +0 +~~END~~ + + +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('sysadmin')) +go +~~START~~ +bit +1 +~~END~~ + + +select is_srvrolemember ('sysadmin') +go +~~START~~ +int +1 +~~END~~ + + +select is_srvrolemember ('securityadmin') +go +~~START~~ +int +1 +~~END~~ + + +select current_user, db_name() +go +~~START~~ +varchar#!#nvarchar +dbo#!#master +~~END~~ + + +CREATE ROLE securityadmin_restrictions_role; +GO + + +-- a tsql login should not be able to drop securityadmin explicitly from tsql port +-- should be denied +ALTER ROLE securityadmin_restrictions_role ADD MEMBER securityadmin; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: role "master_securityadmin" does not exist)~~ + + +DROP LOGIN securityadmin; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot drop the login 'securityadmin', because it does not exist or you do not have permission.)~~ + + +DROP ROLE securityadmin_restrictions_role; +GO + +-- terminate-tsql-conn user=securityadmin_restrict_new_login password=12345678 + +-- psql +create role securityadmin_restrict_new_pg_role +go + +-- psql user=securityadmin_restrict_new_login password=12345678 +-- a tsql login should not be able to alter/grant/drop securityadmin from pg port +ALTER ROLE securityadmin NOCREATEROLE; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE securityadmin WITH PASSWORD '12345678'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE securityadmin VALID UNTIL 'infinity'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE securityadmin WITH CONNECTION LIMIT 1; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT securityadmin TO securityadmin_restrict_new_login; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT securityadmin TO securityadmin_restrict_new_pg_role +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT sysadmin TO securityadmin +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT securityadmin TO securityadmin +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT securityadmin_restrict_new_login TO securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +REVOKE securityadmin FROM master_dbo; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +REVOKE master_dbo FROM securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +DROP ROLE securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be dropped or altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +SET SESSION AUTHORIZATION securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set session authorization + Server SQLState: 42501)~~ + + +SET ROLE securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set role "securityadmin" + Server SQLState: 42501)~~ + + +-- try granting object ownership to securityadmin +ALTER schema master_securityadmin_scm1 owner to securityadmin; +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: must be able to SET ROLE "securityadmin" + Server SQLState: 42501)~~ + + +ALTER table master_dbo.securityadmin_tb1 owner to securityadmin; +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: must be able to SET ROLE "securityadmin" + Server SQLState: 42501)~~ + + +ALTER procedure master_dbo.securityadmin_proc1 owner to securityadmin; +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: must be able to SET ROLE "securityadmin" + Server SQLState: 42501)~~ + + +ALTER function master_dbo.securityadmin_func1 owner to securityadmin; +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: must be able to SET ROLE "securityadmin" + Server SQLState: 42501)~~ + + +-- psql +-- drop role +drop role securityadmin_restrict_new_pg_role +go + +-- normal PG user +CREATE USER securityadmin_restrictions_pg_user WITH LOGIN CREATEROLE PASSWORD '12345678' inherit; +go + +-- psql user=securityadmin_restrictions_pg_user password=12345678 +-- a normal psql user should not be able to alter/grant/drop securityadmin from pg port +ALTER ROLE securityadmin NOCREATEROLE; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- Altering a role by an underprivileged login should be restricted +alter user securityadmin_restrict_new_login with password '123' +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to alter role + Detail: To change another role's password, the current user must have the CREATEROLE attribute and the ADMIN option on the role. + Server SQLState: 42501)~~ + + +ALTER ROLE securityadmin WITH PASSWORD '12345678'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE securityadmin VALID UNTIL 'infinity'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE securityadmin WITH CONNECTION LIMIT 1; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT securityadmin TO securityadmin_restrict_new_login; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +GRANT securityadmin_restrict_new_login TO securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +REVOKE securityadmin FROM master_dbo; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +REVOKE sysadmin FROM securityadmin +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +REVOKE securityadmin FROM securityadmin +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +REVOKE master_dbo FROM securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +DROP ROLE securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be dropped or altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +SET SESSION AUTHORIZATION securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set session authorization + Server SQLState: 42501)~~ + + +SET ROLE securityadmin; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set role "securityadmin" + Server SQLState: 42501)~~ + + +-- tsql +EXEC sp_dropserver 'server_4229', 'droplogins' +GO + +EXEC sp_dropserver 'Accounts', 'droplogins' +GO + +-- terminate-tsql-conn + +-- psql +-- Drop extension only if not user mapping exists for bbf_server +-- Needed so that same test can be reused in upgrade in conjunction +-- with tests for OPENQUERY +DO +$$ +BEGIN +IF NOT EXISTS (SELECT * FROM pg_user_mappings WHERE srvname = 'bbf_server') THEN + SET client_min_messages = 'error'; + DROP EXTENSION tds_fdw CASCADE; +END IF; +END +$$ +GO + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'securityadmin_restrict_new_login' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go +~~START~~ +bool +t +~~END~~ + + +DROP USER securityadmin_restrictions_pg_user; +GO + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- tsql + +ALTER SERVER ROLE sysadmin drop MEMBER securityadmin_restrict_new_login; +GO + +DROP LOGIN securityadmin_restrict_new_login +GO diff --git a/test/JDBC/expected/single_db/BABEL-2403.out b/test/JDBC/expected/single_db/BABEL-2403.out index cb9a19347f..f23cb91110 100644 --- a/test/JDBC/expected/single_db/BABEL-2403.out +++ b/test/JDBC/expected/single_db/BABEL-2403.out @@ -69,6 +69,8 @@ name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} +name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} +text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_user_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} @@ -146,6 +148,8 @@ name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} +name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_login_ext must also exist in pg_authid"} +text#!#sys#!#name#!#{"Rule": " in babelfish_authid_login_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} text#!#sys#!#name#!#{"Rule": " in babelfish_authid_user_ext must also exist in babelfish_sysdatabases"} name#!#pg_catalog#!#rolname#!#{"Rule": " in babelfish_authid_user_ext must also exist in pg_authid"} diff --git a/test/JDBC/expected/single_db/BABEL-LOGIN-USER-EXT.out b/test/JDBC/expected/single_db/BABEL-LOGIN-USER-EXT.out index 9e09597c85..87a7f7ea48 100644 --- a/test/JDBC/expected/single_db/BABEL-LOGIN-USER-EXT.out +++ b/test/JDBC/expected/single_db/BABEL-LOGIN-USER-EXT.out @@ -277,7 +277,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -3 +4 ~~END~~ @@ -288,7 +288,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -4 +5 ~~END~~ @@ -300,7 +300,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -5 +6 ~~END~~ @@ -388,7 +388,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -4 +5 ~~END~~ @@ -418,7 +418,7 @@ SELECT COUNT(*) FROM sys.babelfish_authid_login_ext; go ~~START~~ int -3 +4 ~~END~~ @@ -489,14 +489,14 @@ ALTER SERVER ROLE db_owner ADD MEMBER dummy; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ ALTER SERVER ROLE db_owner DROP MEMBER dummy; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: only sysadmin role is supported in ALTER SERVER ROLE statement)~~ +~~ERROR (Message: Only fixed server role is supported in ALTER SERVER ROLE statement)~~ CREATE LOGIN err_user WITH PASSWORD = '123'; diff --git a/test/JDBC/expected/sys-server_principals-vu-verify.out b/test/JDBC/expected/sys-server_principals-vu-verify.out index 5290e40805..aef130e734 100644 --- a/test/JDBC/expected/sys-server_principals-vu-verify.out +++ b/test/JDBC/expected/sys-server_principals-vu-verify.out @@ -63,6 +63,7 @@ GO varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 public#!#R#!#SERVER_ROLE#!##!##!##!#1#!#0 +securityadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 sys_server_principals_vu_login_without_sa#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 sysadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 ~~END~~ diff --git a/test/JDBC/input/securityadmin_role-vu-cleanup.mix b/test/JDBC/input/securityadmin_role-vu-cleanup.mix new file mode 100644 index 0000000000..5523e86385 --- /dev/null +++ b/test/JDBC/input/securityadmin_role-vu-cleanup.mix @@ -0,0 +1,63 @@ +-- tsql +drop user securityadmin_user1 +go + +drop user no_securityadmin_user1 +go + +drop login securityadmin_login1 +go + +use securityadmin_db1 +go + +drop user no_securityadmin_user1 +go + +use master +go + +drop login no_securityadmin_login1 +go + +drop database securityadmin_db1 +go + +drop schema securityadmin_scm1 +go + +drop view securityadmin_show_role_mem +go + +drop TRIGGER securityadmin_tggr1 +go + +drop table securityadmin_tb1 +go + +drop view securityadmin_v1 +go + +drop function securityadmin_func1() +go + +drop procedure securityadmin_proc1 +go + +drop procedure securityadmin_create_login_p1 +go + +drop procedure securityadmin_alter_login_p1 +go + +drop procedure securityadmin_drop_login_p1 +go + +drop procedure securityadmin_add_mem_p1 +go + +drop procedure securityadmin_drop_mem_p1 +go + +drop role securityadmin_rol +go \ No newline at end of file diff --git a/test/JDBC/input/securityadmin_role-vu-prepare.mix b/test/JDBC/input/securityadmin_role-vu-prepare.mix new file mode 100644 index 0000000000..6c901dbafa --- /dev/null +++ b/test/JDBC/input/securityadmin_role-vu-prepare.mix @@ -0,0 +1,90 @@ +-- tsql +create login securityadmin_login1 with password = '123' +go + +create login no_securityadmin_login1 with password = '123' +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +-- tsql +create role securityadmin_rol +go + +create database securityadmin_db1 +go + +create schema securityadmin_scm1 +go + +CREATE VIEW securityadmin_show_role_mem AS +SELECT +roles.name AS RolePrincipalName +, members.name AS MemberPrincipalName +FROM sys.server_role_members AS server_role_members +INNER JOIN sys.server_principals AS roles + ON server_role_members.role_principal_id = roles.principal_id +INNER JOIN sys.server_principals AS members + ON server_role_members.member_principal_id = members.principal_id order by MemberPrincipalName; +GO + +create table securityadmin_tb1(a int) +go + +create view securityadmin_v1 as select 1; +go + +create function securityadmin_func1() returns int as begin return 1 end; +go + +create procedure securityadmin_proc1 as begin select 1; end +go + +CREATE TRIGGER securityadmin_tggr1 on securityadmin_tb1 AFTER INSERT AS BEGIN END; +go + +create procedure securityadmin_create_login_p1 as begin create login securityadmin_login_new with password ='123'; end +go + +Grant execute on securityadmin_create_login_p1 to PUBLIC; +go + +create procedure securityadmin_alter_login_p1 as begin alter login securityadmin_login_new with password ='1234'; end +go + +Grant execute on securityadmin_alter_login_p1 to PUBLIC; +go + +create procedure securityadmin_drop_login_p1 as begin drop login securityadmin_login_new; end +go + +Grant execute on securityadmin_drop_login_p1 to PUBLIC; +go + +create procedure securityadmin_add_mem_p1 as begin Alter server role securityadmin add member securityadmin_login_new; end +go + +Grant execute on securityadmin_add_mem_p1 to PUBLIC; +go + +create procedure securityadmin_drop_mem_p1 as begin Alter server role securityadmin drop member securityadmin_login_new; end +go + +Grant execute on securityadmin_drop_mem_p1 to PUBLIC; +go + +use securityadmin_db1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +use master +go \ No newline at end of file diff --git a/test/JDBC/input/securityadmin_role-vu-verify.mix b/test/JDBC/input/securityadmin_role-vu-verify.mix new file mode 100644 index 0000000000..f121db6062 --- /dev/null +++ b/test/JDBC/input/securityadmin_role-vu-verify.mix @@ -0,0 +1,907 @@ +-- tsql +alter login securityadmin_login1 with password='123' +go + +alter login no_securityadmin_login1 with password='123' +go + +-- make login member of securityadmin +Alter server role securityadmin add member securityadmin_login1 +go + +select * from securityadmin_show_role_mem where MemberPrincipalName like 'jdbc_user' or MemberPrincipalName like '%securityadmin_%' +go + +-- should error out +create login securityadmin with password = '123' +go + +-- terminate-tsql-conn + +-- Case 1 - positives +-- securityadmin's login privileges +-- tsql user=securityadmin_login1 password=123 +-- alter server role securityadmin should be allowed +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('securityadmin')) +go + +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('sysadmin')) +go + +Alter server role securityadmin add member no_securityadmin_login1 +go + +Alter server role securityadmin drop member no_securityadmin_login1 +go + +-- create login should be allowed +-- windows login +create login [babel\securityadmin_l1] from windows; +go + +-- password based login +create login securityadmin_l2 with password = '123' +go + +-- alter login should be allowed +-- password based login +alter login securityadmin_l2 with password = '123' +go + +ALTER LOGIN securityadmin_l2 WITH PASSWORD = '1234' OLD_PASSWORD = '123'; +go + +ALTER LOGIN securityadmin_l2 disable; +go + +ALTER LOGIN securityadmin_l2 enable; +go + +ALTER LOGIN securityadmin_l2 with default_database=securityadmin_db1; +go + +-- windows login +alter login [babel\securityadmin_l1] with PASSWORD='123' +go + +ALTER LOGIN [babel\securityadmin_l1] WITH PASSWORD = '1234' OLD_PASSWORD = '123'; +go + +ALTER LOGIN [babel\securityadmin_l1] disable; +go + +ALTER LOGIN [babel\securityadmin_l1] enable; +go + +ALTER LOGIN [babel\securityadmin_l1] with default_database=securityadmin_db1; +go + +-- make altering login member of securityadmin +Alter server role securityadmin add member securityadmin_l2 +go + +-- alter securityadmin member login +-- allowed +alter login securityadmin_l2 with password = '123' +go + +-- drop login should be allowed +-- password based login +drop login securityadmin_l2 +go + +-- windows login +drop login [babel\securityadmin_l1] +go + +-- grant server permissions (currently not supported) +-- few examples +GRANT CONTROL SERVER TO no_securityadmin_login1 +go + +GRANT ALTER ANY EVENT NOTIFICATION TO no_securityadmin_login1 WITH GRANT OPTION; +go + +GRANT ALTER ANY DATABASE TO no_securityadmin_login1; +go + +-- grant database permissions (only connect is supported) + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- allowed +-- tsql user=no_securityadmin_login1 password=123 +use securityadmin_db1 +go + +-- terminate-tsql-conn user=no_securityadmin_login1 password=123 + +-- tsql user=securityadmin_login1 password=123 database=securityadmin_db1 +REVOKE CONNECT FROM no_securityadmin_user1 +go + +-- unsupported +GRANT SHOWPLAN TO no_securityadmin_user1; +go + +GRANT CREATE VIEW TO no_securityadmin_user1 WITH GRANT OPTION; +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 database=securityadmin_db1 + +-- connection revoked +-- tsql user=no_securityadmin_login1 password=123 +use securityadmin_db1 +go + +-- terminate-tsql-conn user=no_securityadmin_login1 password=123 + +-- revoke server permissions (currently not supported) +-- few examples +-- tsql user=securityadmin_login1 password=123 database=securityadmin_db1 +REVOKE CONTROL SERVER FROM no_securityadmin_login1 +go + +REVOKE ALTER ANY EVENT NOTIFICATION FROM no_securityadmin_login1; +go + +REVOKE ALTER ANY DATABASE FROM no_securityadmin_login1; +go + +-- grant database permissions (only connect is supported) +GRANT CONNECT TO no_securityadmin_user1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 database=securityadmin_db1 + +-- tsql user=no_securityadmin_login1 password=123 +use securityadmin_db1 +go + +-- Check unprivileged login should not have access +-- permission denied +EXEC sp_addlinkedsrvlogin 'Accounts', 'False' +GO + +EXEC sp_droplinkedsrvlogin 'Accounts', NULL +GO + +Alter server role securityadmin add member no_securityadmin_login1 +GO + +Alter server role securityadmin drop member no_securityadmin_login1 +GO + +-- only current login and fixed server roles +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals ORDER BY name +GO + +-- only current login +select name, type, usage from sys.login_token order by name; +go + +-- terminate-tsql-conn user=no_securityadmin_login1 password=123 + +-- tsql user=securityadmin_login1 password=123 +-- unsupported +REVOKE SHOWPLAN FROM no_securityadmin_user1; +go + +REVOKE CREATE VIEW FROM no_securityadmin_user1; +go + +-- System objects +-- All rows of server_prinicipals view should be visible to securityadmin login +-- limited rows should get displayed +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals +WHERE name in ('jdbc_user', 'sysadmin', 'public', 'securityadmin') ORDER BY name; +GO + +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals name WHERE name like '%securityadmin%' ORDER BY name; +GO + +-- current login along with current fixed role should be visible +select name, type, usage from sys.login_token order by name; +go + +select name, sysadmin, securityadmin from syslogins where name like '%securityadmin%' order by name +go + +-- should return 0 +select is_srvrolemember ('sysadmin') +go + +-- should return 1 +select is_srvrolemember ('securityadmin') +go + +select is_srvrolemember ('securityadmin', 'securityadmin_login1') +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- psql +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +-- Add localhost as linked server +EXEC sp_addlinkedserver @server = N'server_4229', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +EXEC sp_addlinkedserver 'Accounts' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'server_4229', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +drop database securityadmin_db1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +EXEC sp_addlinkedsrvlogin 'Accounts', 'False' +GO + +EXEC sp_droplinkedsrvlogin 'Accounts', NULL +GO + +-- inside procedure +exec securityadmin_create_login_p1 +go + +exec securityadmin_alter_login_p1 +go + +exec securityadmin_add_mem_p1 +go + +exec securityadmin_drop_mem_p1 +go + +exec securityadmin_drop_login_p1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- login is member of both securityadmin as well as sysadmin +-- tsql +drop user securityadmin_user1 +go + +Alter server role sysadmin add member securityadmin_login1 +go + +create database securityadmin_db1 +go + +-- terminate-tsql-conn + +-- it should be able to connect to the database +-- tsql user=securityadmin_login1 password=123 +use securityadmin_db1 +go + +-- it should be dbo +select current_user +go + +-- both attribute should be true +select rolname, rolcreaterole, rolcreatedb from pg_roles where rolname = 'securityadmin_login1' +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- only member of securityadmin +-- tsql +alter server role sysadmin drop member securityadmin_login1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 + +-- only rolcreaterole attribute should be true +select rolname, rolcreaterole, rolcreatedb from pg_roles where rolname = 'securityadmin_login1' +go + +-- should be able to create/drop login +create login test_securityadmin_l1 with password ='123' +go + +drop login test_securityadmin_l1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- only member of sysadmin +drop user securityadmin_user1 +go + +alter server role sysadmin add member securityadmin_login1 +go + +alter server role securityadmin drop member securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 + +-- both attribute should be true +select rolname, rolcreaterole, rolcreatedb from pg_roles where rolname = 'securityadmin_login1' +go + +-- should be able to create/drop login +create login test_securityadmin_l1 with password ='123' +go + +drop login test_securityadmin_l1 +go + +-- should return 1 +select is_srvrolemember ('sysadmin') +go + +-- should return 1 +select is_srvrolemember ('securityadmin') +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- make it member of securityadmin only +alter server role sysadmin drop member securityadmin_login1 +go + +alter server role securityadmin add member securityadmin_login1 +go + +drop user no_securityadmin_user1 +go + +alter server role sysadmin add member no_securityadmin_login1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- Case 2 - negatives +-- alter server role sysadmin should give permission denied +Alter server role sysadmin add member no_securityadmin_login1 +go + +-- alter server role securityadmin add member db roles should error out +Alter server role securityadmin add member guest +go + +-- alter sysadmin login should give permission denied +-- login which is altered is member of sysadmin +Alter login no_securityadmin_login1 with password ='123' +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +-- make member of securityadmin as well +alter server role securityadmin add member no_securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- login which is altered is member of sysadmin and securityadmin both +-- permission denied +Alter login no_securityadmin_login1 with password ='123' +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +alter server role securityadmin drop member no_securityadmin_login1 +go + +alter server role sysadmin drop member no_securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +create role dummy_role +go + +drop database securityadmin_db1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- should error out +Alter server role securityadmin add member dummy_role +go + +-- create database permission denied +create database perm_denied_db +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- tsql +drop role dummy_role +go + +create database securityadmin_db1 +go + +use securityadmin_db1 +go + +create user securityadmin_user1 for login securityadmin_login1 +go + +create user no_securityadmin_user1 for login no_securityadmin_login1 +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_login1 password=123 +-- alter database permission denied +alter database securityadmin_db1 modify name = rename_db_database1; +go + +alter authorization on database::securityadmin_db1 to no_securityadmin_login1 +go + +-- drop database permission denied +drop database securityadmin_db1 +go + +-- securityadmin login's mapped user should not have any priv +select current_user, db_name() +go + +select suser_name() +go + +-- allowed +create login securityadmin_l2 with password = '123' +go + +-- create objects/user permission denied +create user securityadmin_l2 +go + +create role securityadmin_role1 +go + +create schema perm_denied_scm +go + +create view perm_denied_v1 as select 1; +go + +create table perm_denied_tb1 (a int); +go + +select 1 into perm_denied_tb2; +go + +create function perm_denied_func1() returns int as begin return 1 end; +go + +create procedure perm_denied_proc1 as begin select 1; end +go + +create type perm_denied_typ1 from int; +go + +create index perm_denied_index1 on securityadmin_tb1(a); +go + +CREATE FUNCTION perm_denied_func1() RETURNS TABLE AS RETURN ( SELECT 1 AS Value); +go + +-- DMLS on object permission denied +Alter user no_securityadmin_user1 with DEFAULT_SCHEMA=securityadmin_scm1 +go + +Alter role securityadmin_rol add member no_securityadmin_user1 +go + +Alter role securityadmin_rol drop member no_securityadmin_user1 +go + +Alter table securityadmin_tb1 add b int +go + +Insert into securityadmin_tb1 values (1) +go + +UPDATE securityadmin_tb1 SET a = 2 where a = 1; +go + +DELETE FROM securityadmin_tb1 WHERE a = 1; +go + +TRUNCATE TABLE securityadmin_tb1; +go + +select * from securityadmin_tb1 +go + +select * from securityadmin_v1 +go + +select securityadmin_func1() +go + +exec securityadmin_proc1 +go + +Enable trigger securityadmin_tggr1 on securityadmin_tb1 +go + +Disable trigger securityadmin_tggr1 on securityadmin_tb1 +go + +-- grant on objects permission denied +Grant select on securityadmin_tb1 to no_securityadmin_user1 +go + +Grant update on securityadmin_v1 to no_securityadmin_user1 +go + +Grant update on securityadmin_v1 to no_securityadmin_user1 +go + +Grant exec on securityadmin_func1 to no_securityadmin_user1 +go + +Grant exec on securityadmin_proc1 to no_securityadmin_user1 +go + +-- Revoke on objects permission denied +Revoke select on securityadmin_tb1 from no_securityadmin_user1 +go + +Revoke update on securityadmin_v1 from no_securityadmin_user1 +go + +Revoke update on securityadmin_v1 from no_securityadmin_user1 +go + +Revoke exec on securityadmin_func1 from no_securityadmin_user1 +go + +Revoke exec on securityadmin_proc1 from no_securityadmin_user1 +go + +-- grant on schema +-- permission denied +grant select on securityadmin_v1 to no_securityadmin_user1; +go +grant select on dbo.securityadmin_v1 to no_securityadmin_user1; +go +grant execute on securityadmin_proc1 to no_securityadmin_user1; +go +grant execute on dbo.securityadmin_proc1 to no_securityadmin_user1; +go + +-- revoke on schema +-- permission denied +revoke select on securityadmin_v1 from no_securityadmin_user1; +go +revoke select on dbo.securityadmin_v1 from no_securityadmin_user1; +go +revoke execute on securityadmin_proc1 from no_securityadmin_user1; +go +revoke execute on dbo.securityadmin_proc1 from no_securityadmin_user1; +go + +-- drop object permission denied +drop user securityadmin_l2 +go + +drop role securityadmin_rol +go + +drop schema securityadmin_scm1 +go + +drop view securityadmin_show_role_mem +go + +drop TRIGGER securityadmin_tggr1 +go + +drop table securityadmin_tb1 +go + +drop view securityadmin_v1 +go + +drop function securityadmin_func1() +go + +drop procedure securityadmin_proc1 +go + +-- allowed drop login +drop login securityadmin_l2 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- securityadmin login should not get mapped to dbo if no user exist, it should disconnect + +-- tsql database=securityadmin_db1 +drop user securityadmin_user1 +go + +-- terminate-tsql-conn database=securityadmin_db1 + +-- it should disconnect +-- tsql user=securityadmin_login1 password=123 +use securityadmin_db1 +go + +-- Case 3 - alter server role other than securityadmin and sysadmin should give unsupported +-- tsql +Alter server role false_role add member no_securityadmin_login1 +go + +Alter server role serveradmin add member no_securityadmin_login1 +go + +Alter server role setupadmin add member no_securityadmin_login1 +go + +Alter server role processadmin add member no_securityadmin_login1 +go + +Alter server role diskadmin add member no_securityadmin_login1 +go + +Alter server role bulkadmin add member no_securityadmin_login1 +go + +Alter server role false_role drop member no_securityadmin_login1 +go + +Alter server role serveradmin drop member no_securityadmin_login1 +go + +Alter server role setupadmin drop member no_securityadmin_login1 +go + +Alter server role processadmin drop member no_securityadmin_login1 +go + +Alter server role diskadmin drop member no_securityadmin_login1 +go + +Alter server role bulkadmin drop member no_securityadmin_login1 +go + +-- terminate-tsql-conn user=securityadmin_login1 password=123 + +-- Case 4 - check unintended/unauthorized use of securityadmin +-- tsql +CREATE LOGIN securityadmin_restrict_new_login WITH password = '12345678'; +go + +ALTER SERVER ROLE sysadmin ADD MEMBER securityadmin_restrict_new_login; +GO + +select * from securityadmin_show_role_mem where MemberPrincipalName like 'jdbc_user' or MemberPrincipalName like '%securityadmin_%' +go + +-- terminate-tsql-conn + +-- tsql user=securityadmin_restrict_new_login password=12345678 +select * from securityadmin_show_role_mem where MemberPrincipalName like 'jdbc_user' or MemberPrincipalName like '%securityadmin_%' +go + +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('securityadmin')) +go + +select bbf_is_member_of_role_nosuper(suser_id(), suser_id('sysadmin')) +go + +select is_srvrolemember ('sysadmin') +go + +select is_srvrolemember ('securityadmin') +go + +select current_user, db_name() +go + +CREATE ROLE securityadmin_restrictions_role; +GO + +-- a tsql login should not be able to drop securityadmin explicitly from tsql port + +-- should be denied +ALTER ROLE securityadmin_restrictions_role ADD MEMBER securityadmin; +GO + +DROP LOGIN securityadmin; +GO + +DROP ROLE securityadmin_restrictions_role; +GO + +-- terminate-tsql-conn user=securityadmin_restrict_new_login password=12345678 + +-- psql +create role securityadmin_restrict_new_pg_role +go + +-- psql user=securityadmin_restrict_new_login password=12345678 +-- a tsql login should not be able to alter/grant/drop securityadmin from pg port +ALTER ROLE securityadmin NOCREATEROLE; +GO + +ALTER ROLE securityadmin WITH PASSWORD '12345678'; +GO + +ALTER ROLE securityadmin VALID UNTIL 'infinity'; +GO + +ALTER ROLE securityadmin WITH CONNECTION LIMIT 1; +GO + +GRANT securityadmin TO securityadmin_restrict_new_login; +GO + +GRANT securityadmin TO securityadmin_restrict_new_pg_role +GO + +GRANT sysadmin TO securityadmin +go + +GRANT securityadmin TO securityadmin +go + +GRANT securityadmin_restrict_new_login TO securityadmin; +GO + +REVOKE securityadmin FROM master_dbo; +GO + +REVOKE master_dbo FROM securityadmin; +GO + +DROP ROLE securityadmin; +GO + +SET SESSION AUTHORIZATION securityadmin; +GO + +SET ROLE securityadmin; +GO + +-- try granting object ownership to securityadmin +ALTER schema master_securityadmin_scm1 owner to securityadmin; +go + +ALTER table master_dbo.securityadmin_tb1 owner to securityadmin; +go + +ALTER procedure master_dbo.securityadmin_proc1 owner to securityadmin; +go + +ALTER function master_dbo.securityadmin_func1 owner to securityadmin; +go + +-- psql +-- drop role +drop role securityadmin_restrict_new_pg_role +go + +-- normal PG user +CREATE USER securityadmin_restrictions_pg_user WITH LOGIN CREATEROLE PASSWORD '12345678' inherit; +go + +-- psql user=securityadmin_restrictions_pg_user password=12345678 +-- a normal psql user should not be able to alter/grant/drop securityadmin from pg port +ALTER ROLE securityadmin NOCREATEROLE; +GO + +-- Altering a role by an underprivileged login should be restricted +alter user securityadmin_restrict_new_login with password '123' +go + +ALTER ROLE securityadmin WITH PASSWORD '12345678'; +GO + +ALTER ROLE securityadmin VALID UNTIL 'infinity'; +GO + +ALTER ROLE securityadmin WITH CONNECTION LIMIT 1; +GO + +GRANT securityadmin TO securityadmin_restrict_new_login; +GO + +GRANT securityadmin_restrict_new_login TO securityadmin; +GO + +REVOKE securityadmin FROM master_dbo; +GO + +REVOKE sysadmin FROM securityadmin +go + +REVOKE securityadmin FROM securityadmin +go + +REVOKE master_dbo FROM securityadmin; +GO + +DROP ROLE securityadmin; +GO + +SET SESSION AUTHORIZATION securityadmin; +GO + +SET ROLE securityadmin; +GO + +-- tsql +EXEC sp_dropserver 'server_4229', 'droplogins' +GO + +EXEC sp_dropserver 'Accounts', 'droplogins' +GO + +-- terminate-tsql-conn + +-- psql +-- Drop extension only if not user mapping exists for bbf_server +-- Needed so that same test can be reused in upgrade in conjunction +-- with tests for OPENQUERY +DO +$$ +BEGIN +IF NOT EXISTS (SELECT * FROM pg_user_mappings WHERE srvname = 'bbf_server') THEN + SET client_min_messages = 'error'; + DROP EXTENSION tds_fdw CASCADE; +END IF; +END +$$ +GO + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'securityadmin_restrict_new_login' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go + +DROP USER securityadmin_restrictions_pg_user; +GO + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO + +-- tsql + +ALTER SERVER ROLE sysadmin drop MEMBER securityadmin_restrict_new_login; +GO + +DROP LOGIN securityadmin_restrict_new_login +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/15_5/schedule b/test/JDBC/upgrade/15_5/schedule index 653392737e..dd85658980 100644 --- a/test/JDBC/upgrade/15_5/schedule +++ b/test/JDBC/upgrade/15_5/schedule @@ -535,4 +535,4 @@ xml_exist-before-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 BABEL-2736-before-16_5 - +securityadmin_role diff --git a/test/JDBC/upgrade/15_6/schedule b/test/JDBC/upgrade/15_6/schedule index bcb8505b3e..4487e73387 100644 --- a/test/JDBC/upgrade/15_6/schedule +++ b/test/JDBC/upgrade/15_6/schedule @@ -551,4 +551,4 @@ xml_exist-before-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 BABEL-2736-before-16_5 - +securityadmin_role diff --git a/test/JDBC/upgrade/15_7/schedule b/test/JDBC/upgrade/15_7/schedule index 5a567ebdf7..3db746d9b8 100644 --- a/test/JDBC/upgrade/15_7/schedule +++ b/test/JDBC/upgrade/15_7/schedule @@ -559,4 +559,4 @@ GRANT_SCHEMA-before-15_9-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 BABEL-2736-before-16_5 - +securityadmin_role diff --git a/test/JDBC/upgrade/15_8/schedule b/test/JDBC/upgrade/15_8/schedule index 27704e1a12..a781dcf080 100644 --- a/test/JDBC/upgrade/15_8/schedule +++ b/test/JDBC/upgrade/15_8/schedule @@ -550,4 +550,4 @@ GRANT_SCHEMA-before-15_9-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 BABEL-2736-before-16_5 - +securityadmin_role diff --git a/test/JDBC/upgrade/15_9/schedule b/test/JDBC/upgrade/15_9/schedule index 0bd29ab197..1d24d56ddb 100644 --- a/test/JDBC/upgrade/15_9/schedule +++ b/test/JDBC/upgrade/15_9/schedule @@ -544,6 +544,7 @@ replace binary-datatype-operators BABEL-5059_before_16_5 SELECT_INTO_TEST +securityadmin_role cast-varchar-to-time xml_exist-before-16_5 BABEL-5119_before_16_5 diff --git a/test/JDBC/upgrade/16_1/schedule b/test/JDBC/upgrade/16_1/schedule index 61d28ed6e4..9c34e884e4 100644 --- a/test/JDBC/upgrade/16_1/schedule +++ b/test/JDBC/upgrade/16_1/schedule @@ -540,6 +540,7 @@ replace-before-15_8-or-16_4 binary-datatype-operators BABEL-5059_before_16_5 cast-varchar-to-time +securityadmin_role xml_exist-before-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 diff --git a/test/JDBC/upgrade/16_2/schedule b/test/JDBC/upgrade/16_2/schedule index 0ac7b277bc..469b203d3a 100644 --- a/test/JDBC/upgrade/16_2/schedule +++ b/test/JDBC/upgrade/16_2/schedule @@ -559,4 +559,4 @@ xml_exist-before-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 BABEL-2736-before-16_5 - +securityadmin_role diff --git a/test/JDBC/upgrade/16_3/schedule b/test/JDBC/upgrade/16_3/schedule index 30063ca952..7458240998 100644 --- a/test/JDBC/upgrade/16_3/schedule +++ b/test/JDBC/upgrade/16_3/schedule @@ -563,3 +563,4 @@ GRANT_SCHEMA-before-15_9-16_5 BABEL-CASE_EXPR-before-16_5-or-15_9 BABEL-5186 BABEL-2736-before-16_5 +securityadmin_role diff --git a/test/JDBC/upgrade/16_4/schedule b/test/JDBC/upgrade/16_4/schedule index 462ecd4d86..845a127d5a 100644 --- a/test/JDBC/upgrade/16_4/schedule +++ b/test/JDBC/upgrade/16_4/schedule @@ -576,3 +576,4 @@ BABEL-CASE_EXPR-before-16_5-or-15_9 charindex_replace_patindex BABEL-5186 BABEL-2736-before-16_5 +securityadmin_role diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index d7aeb3a57c..585be33b03 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -572,6 +572,7 @@ replicate space SELECT_INTO_TEST binary-datatype-operators +securityadmin_role sys_dm_os_sys_info BABEL-5059 cast-varchar-to-time diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index db033f06c7..d45b122b01 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -215,6 +215,7 @@ Function sys.bbf_binary_varbinary_cmp(sys.bbf_binary,sys.bbf_varbinary) Function sys.bbf_get_context_info() Function sys.bbf_get_current_physical_schema_name(text) Function sys.bbf_get_immediate_base_type_of_udt(oid) +Function sys.bbf_is_member_of_role_nosuper(oid,oid) Function sys.bbf_is_shared_schema(text) Function sys.bbf_string_agg_finalfn_nvarchar(internal) Function sys.bbf_string_agg_finalfn_varchar(internal)