Blog Post

sp_SrvPermissions

,

Last week I posted my stored procedure for database permissions, sp_DBPermissions. A couple of days later I was demonstrating it to one of my co-workers and his response was “Where’s the server version?” Unable to come up with an appropriate rude response I’m posting the server version this week, sp_SrvPermissions.

It has the same basic setup. It returns three data sets, a list of principals, a list of role membership, and a list of server level permissions. The information can be narrowed down by passing in a principal and/or role name. Additional details are in the comments of the SP itself. If you create the stored procedure in master you will be able to call it from anywhere on the instance because the name begins with sp_.

/*********************************************************************************************
sp_SrvPermissions V1.0
Kenneth Fisher
http://www.sqlstudies.com
This stored procedure returns 3 data sets.  The first dataset is the list of server
principals, the second is role membership, and the third is server level permissions.
 
The final 2 columns of each query are "Un-Do"/"Do" scripts.  For example removing a member
from a role or adding them to a role.  I am fairly confident in the role scripts, however, 
the scripts in the server principals query and server permissions query are works in 
progress.  In particular certificates and keys are not scripted out.  Also while the scripts 
have worked flawlessly on the systems I've tested them on, these systems are fairly similar 
when it comes to security so I can't say that in a more complicated system there won't be 
the odd bug.
Notes on the create script for server principals:
1)I have included a hashed version of the password and the sid.  This means that when run
on another server the password and the sid will remain the same.  
2)In SQL 2005 the create script on the server principals query DOES NOT WORK.  This is 
because the conversion of the sid (in varbinary) to character doesn't appear to work 
as I expected in SQL 2005.  It works fine in SQL 2008 and above.  If you want to use
this script in SQL 2005 you can change the CONVERTs in the principal script to 
master.sys.fn_varbintohexstr
Standard disclaimer: You use scripts off of the web at your own risk.  I fully expect this
     script to work without issue but I've been known to be wrong before.
 
Parameters:
    @Principal
        If NOT NULL then all three queries only pull for that server principal.  @Principal
        is a pattern check.  The queries check for any row where the passed in value exists.
        It uses the pattern '%' + @Principal + '%'
    @Role
        If NOT NULL then the roles query will pull members of the role.  If it is NOT NULL and
        @Principal is NULL then Server principal and permissions query will pull the principal 
        row for the role and the permissions for the role.  @Role is a pattern check.  The 
        queries check for any row where the passed in value exists.  It uses the pattern 
        '%' + @Role + '%'
    @Print
        Defaults to 0, but if a 1 is passed in then the queries are not run but printed
        out instead.  This is primarily for debugging.
     
*********************************************************************************************/ALTER PROCEDURE dbo.sp_SrvPermissions 
(
@Principal sysname = NULL, 
@Role sysname = NULL, 
@Print bit = 0
)
AS
DECLARE @Collation nvarchar(50) 
SET @Collation = ' COLLATE ' + CAST(SERVERPROPERTY('Collation') AS nvarchar(50))
DECLARE @sql nvarchar(max)
 
IF LEN(ISNULL(@Principal,'')) > 0
    SET @Principal = '%' + @Principal + '%'
     
IF LEN(ISNULL(@Role,'')) > 0
    SET @Role = '%' + @Role+ '%'
 
--=========================================================================
-- Server Principals
SET @sql = 
'SELECT name AS SrvPrincipal, sid, type, type_desc, is_disabled, default_database_name, default_language_name, ' + CHAR(13) + 
'CASE WHEN principal_id < 100 THEN NULL ELSE ' + CHAR(13) + 
'''DROP '' + CASE [type] WHEN ''C'' THEN NULL ' + CHAR(13) + 
'WHEN ''K'' THEN NULL ' + CHAR(13) + 
'WHEN ''R'' THEN ''ROLE'' ' + CHAR(13) + 
'ELSE ''LOGIN'' END + ' + CHAR(13) + 
''' ''+QUOTENAME(name' + @Collation + ') END + '';'' AS Drop_Script, ' + CHAR(13) + 
'CASE WHEN principal_id < 100 THEN NULL ELSE ' + CHAR(13) + 
'''CREATE '' + CASE [type] WHEN ''C'' THEN NULL ' + CHAR(13) + 
'WHEN ''K'' THEN NULL ' + CHAR(13) + 
'WHEN ''R'' THEN ''ROLE'' ' + CHAR(13) + 
'ELSE ''LOGIN'' END + ' + CHAR(13) + 
''' ''+QUOTENAME(name' + @Collation + ') END + ' + CHAR(13) + 
'CASE WHEN [type] = (''S'') THEN ' + CHAR(13) + 
''' WITH PASSWORD = '' + ' + CHAR(13) + 
'CONVERT(varchar(256), LOGINPROPERTY(name, ''PasswordHash''),1 ) + '' HASHED,'' +  ' + CHAR(13) + 
''' SID = '' + CONVERT(varchar(85), sid, 1) +  ' + CHAR(13) + 
'CASE WHEN default_database_name IS NOT NULL OR default_language_name IS NOT NULL THEN '','' ELSE '''' END ' + CHAR(13) + 
'WHEN [type] IN (''U'',''G'') THEN '' FROM WINDOWS '' + ' + CHAR(13) + 
'CASE WHEN default_database_name IS NOT NULL OR default_language_name IS NOT NULL THEN '' WITH '' ELSE '''' END ' + CHAR(13) + 
'ELSE '''' END + ' + CHAR(13) + 
'ISNULL('' DEFAULT_DATABASE = '' + QUOTENAME(default_database_name' + @Collation + '), '''') + ' + CHAR(13) + 
'CASE WHEN default_database_name IS NOT NULL AND default_language_name IS NOT NULL THEN '','' ELSE '''' END + ' + CHAR(13) + 
'ISNULL('' DEFAULT_LANGUAGE = '' + QUOTENAME(default_language_name' + @Collation + '), '''') + ' + CHAR(13) + 
''';'' ' + CHAR(13) + 
'AS Create_Script ' + CHAR(13) + 
'FROM sys.server_principals Logins '
IF LEN(ISNULL(@Principal,@Role)) > 0 
    SET @sql = @sql + CHAR(13) + 'WHERE Logins.name LIKE ISNULL(@Principal,@Role) '
 
IF @Print = 1
    PRINT '-- Server Principals' + CHAR(13) + @sql + CHAR(13) + CHAR(13)
ELSE
    EXEC sp_executesql @sql, N'@Principal sysname, @Role sysname', @Principal, @Role
 
--=========================================================================
-- Server level roles
SET @sql = 
'SELECT Logins.name AS UserName, Roles.name AS RoleName, ' + CHAR(13) + 
'''EXEC sp_dropsrvrolemember ''+QUOTENAME(Roles.name' + @Collation + 
','''''''')+'',''+QUOTENAME(Logins.name' + @Collation + 
','''''''') + '';'', ' + CHAR(13) + 
'''EXEC sp_addsrvrolemember ''+QUOTENAME(Roles.name' + @Collation + 
','''''''')+'',''+QUOTENAME(Logins.name' + @Collation + 
','''''''') + '';'' ' + CHAR(13) + 
'FROM sys.server_role_members RoleMembers ' + CHAR(13) + 
'JOIN sys.server_principals Logins ' + CHAR(13) + 
'ON RoleMembers.member_principal_id = Logins.principal_id ' + CHAR(13) + 
'JOIN sys.server_principals Roles ' + CHAR(13) + 
'ON RoleMembers.role_principal_id = Roles.principal_id ' + CHAR(13) + 
    'WHERE 1=1 '
IF LEN(ISNULL(@Principal,'')) > 0
    SET @sql = @sql + CHAR(13) + '  AND Logins.name LIKE @Principal'
 
IF LEN(ISNULL(@Role,'')) > 0
    SET @sql = @sql + CHAR(13) + '  AND Roles.name LIKE @Role'
 
IF @Print = 1
    PRINT '-- Server Role Members' + CHAR(13) + @sql + CHAR(13) + CHAR(13)
ELSE
    EXEC sp_executesql @sql, N'@Principal sysname, @Role sysname', @Principal, @Role
 
--=========================================================================
-- Database & object Permissions
SET @sql =
'SELECT Grantee.name AS Grantee_Name, Grantor.name AS Grantor_Name, ' + CHAR(13) + 
'Permission.class_desc, Permission.permission_name, ' + CHAR(13) + 
'Permission.state_desc,  ' + CHAR(13) + 
'''REVOKE '' + ' + CHAR(13) + 
'CASE WHEN Permission.class_desc = ''ENDPOINT'' THEN NULL ' + CHAR(13) + 
'WHEN Permission.[state]  = ''W'' THEN ''GRANT OPTION FOR '' ELSE '''' END + ' + CHAR(13) + 
''' '' + Permission.permission_name' + @Collation + ' +  ' + CHAR(13) + 
''' FROM '' + QUOTENAME(Grantee.name' + @Collation + ')  + ''; '' AS Revoke_Statement, ' + CHAR(13) + 
'CASE WHEN Permission.class_desc = ''ENDPOINT'' THEN NULL ' + CHAR(13) + 
'WHEN Permission.[state]  = ''W'' THEN ''GRANT'' ELSE Permission.state_desc' + @Collation + ' END + ' + CHAR(13) + 
''' '' + Permission.permission_name' + @Collation + ' +  ' + CHAR(13) + 
''' TO '' + QUOTENAME(Grantee.name' + @Collation + ')  + '' '' +  ' + CHAR(13) + 
'CASE WHEN Permission.[state]  = ''W'' THEN '' WITH GRANT OPTION '' ELSE '''' END +  ' + CHAR(13) + 
''' AS ''+ QUOTENAME(Grantor.name' + @Collation + ') + '';'' AS Grant_Statement ' + CHAR(13) + 
'FROM sys.server_permissions Permission ' + CHAR(13) + 
'JOIN sys.server_principals Grantee ' + CHAR(13) + 
'ON Permission.grantee_principal_id = Grantee.principal_id ' + CHAR(13) + 
'JOIN sys.server_principals Grantor ' + CHAR(13) + 
'ON Permission.grantor_principal_id = Grantor.principal_id ' 
IF LEN(ISNULL(@Principal,@Role)) > 0
    SET @sql = @sql + CHAR(13) + 'WHERE Grantee.name LIKE ISNULL(@Principal,@Role) '
 
IF @Print = 1
    PRINT '-- Server Permissions' + CHAR(13) + @sql + CHAR(13) + CHAR(13)
ELSE
    EXEC sp_executesql @sql, N'@Principal sysname, @Role sysname', @Principal, @Role
GO

Filed under: Dynamic SQL, Microsoft SQL Server, Security, SQLServerPedia Syndication Tagged: code language, dynamic sql, language sql, microsoft sql server, security, T-SQL

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating