Check if a user can run the RECONFIGURE statement - sql-server

I'm using SQL Server Express on AWS and, when trying to change the MAXDOP via a T-SQL query, I got an error stating
Database Error: [Microsoft][SQL Server Native Client 11.0][SQL
Server]User does not have permission to perform this action. (37000:
15,247) ... You do not have permission to run the RECONFIGURE
statement (37000: 5,812).
I suppose this can also happen on SQL Server instances that are not on AWS, it seems to be a user permission problem.
Is there a way to programmatically check if a user can (or cannot) run the RECONFIGURE statement, preferably running a T-SQL query on SQL Server >= 2014?

The RECONFIGURE statement requires the server-level ALTER SETTINGS permission. The fn_my_permissions TVF can be used programmatically to check if the current user has the permission:
IF NOT EXISTS(
SELECT 1
FROM fn_my_permissions(NULL, 'server')
WHERE permission_name = N'ALTER SETTINGS'
)
BEGIN
PRINT N'Current user does not have ALTER SETTINGS permission needed for RECONFIGURE statement';
END;
Alternatively per the comment by #lptr, one can use the HAS_PERMS_BY_NAME scalar function:
IF HAS_PERMS_BY_NAME(NULL, NULL, 'ALTER SETTINGS') = 0
BEGIN
PRINT N'Current user does not have ALTER SETTINGS permission needed for RECONFIGURE statement';
END;

Related

xp_cmdshell access in SQL Server

I had inherited a stored procedure from a colleague that uses the xp_cmdshell within it. In order to enable this feature for the particular login, I need to run the following commands to enable it.
EXEC sp_configure 'show advanced options', 1
GO
-- To update the currently configured value for advanced options.
RECONFIGURE
GO
-- To enable the feature.
EXEC sp_configure 'xp_cmdshell', 1
GO
-- To update the currently configured value for this feature.
RECONFIGURE
GO
I had added sysadmin server role access to this particular login, and running this stored procedure require sysadmin access so far.
We had granted this particular user with sysadmin access in the development SQL Server. As we migrate the stored procedure to production environment, DBA had concerns there is too much privilege for this user in production environment.
Is there any way we can continue to run the stored procedure with this login without the sysadmin access in the production environment?
Thank you for your help in advance.
Thanks for all the help. I am continuing the comment here as I need markup for the sample code.
The stored procedure tries to perform basic file IO operation to move, copy, delete files to a network drive.
e.g. exec #ret_val = master..xp_cmdshell #stmt, no_output #stmt
#stmt can be "copy //hostname/mapdrive/subdirectory/somefile //hostname/mapped directory" using sharing mechanism.
or create a subdirectory.
e.g. select #stmt = 'md '+#pri_path
I believe they perform this using stored procedure so they can contain all the file I/O operation within the stored procedure.
As for the xp_cmd_shell_proxy_account, I found this https://msdn.microsoft.com/en-us/library/ms190359.aspx. Based on my interpretation, we are providing a windows login username and password to the sql server to gain access to a shell. Am I correct?
Thanks.

Cannot alter the server role 'bulkadmin' in side SP

i have application and sql server 2012 user ( i need to keep him with minimum permission)
i need to perform bulk insert by my application .
so i need to grant and deny the bulk permission by using SP
when i try
Alter PROCEDURE grantRole #Grant bit
With Execute As Owner AS
if(#Grant=1)
ALTER SERVER ROLE [bulkadmin] ADD MEMBER [myUser]
else
ALTER SERVER ROLE [bulkadmin] DROP MEMBER [myUser]
GO
i get the error
Msg 15151, Level 16, State 1, Line 1
Cannot alter the server role 'bulkadmin', because it does not exist or you do not have permission.
note that :the SP 'grantRole' exec from my application by the connection of the user -which is the user need to grant/deny the role- with execute permission
but as developer i have the permission
how can i solved or is their another way

Cannot enable select into/bulkcopy on SQL Server 2005 database using sp_dboption

I am trying to enable the select into/bulkcopy database option on a SQL Server 2005 database using the command:
EXEC sp_dboption 'mydbname', 'select into/bulkcopy', 'true'
After executing the above, running EXEC sp_dboption 'mydbname', 'select into/bulkcopy' tells me that the option is still set to OFF.
I've confirmed that my Windows login is a user in the database and that it belongs to the db_owner role. Having read the MSDN Documentation for sp_dboption, this appears to be the only prerequisite for using the procedure to change options on a database.
Are there any other steps or settings I am missing that could prevent me from being able to enable this option?
That procedure is deprecated. You can use
ALTER DATABASE [mydbname] SET RECOVERY BULK_LOGGED WITH NO_WAIT
This seems to happen if your DB is currently in SIMPLE recovery model.
Looking at the sp_dboption procedure definition the relevant bit of code is
if #alt_optvalue = 'ON'
begin
if databaseproperty(#dbname, 'IsTrunclog') = 1
select #alt_optvalue = 'RECMODEL_70BACKCOMP'
else
select #alt_optvalue = 'BULK_LOGGED'
end
The effect of running ALTER DATABASE [mydbname] SET RECOVERY RECMODEL_70BACKCOMP WITH NO_WAIT seems to be to set the recovery model to SIMPLE so basically it has no effect in this instance

Current transaction ID in an audit trigger

I was looking at storing some form of transaction id from an audit trigger. The solution appeared to be to use sys.dm_tran_current_transaction as in this post SQL Server Triggers - grouping by transactions.
However, I cannot use this because the user account running sql statements will not have the "VIEW SERVER STATE" permission and results in the error:
Msg 297, Level 16, State 1, Line 3
The user does not have permission to perform this action.
Does anyone know of an alternative to this view that will provide a similar transaction id or a way to use "WITH EXECUTE AS" on the trigger to allow selecting from this view.
From my attempts at "WITH EXECUTE AS" it appears that server level permissions are not carried over, which is expected really since it is impersonating a database user.
You can resolve almost any security problem using code signing. Most granular and finely tuned access control, is just a bit on the hard side to understand.
Use EXECUTE AS OWNER on the trigger, create a certificate, sign the trigger, drop the private key (so that noone else can use it to ever sign anything again), export the certificate (public key only), import the certificate in master, create a login derived from the certificate, grant authenticate to this login (in order to extend the database execute as impersonation), then grant view server state to this login. This is bullet proof, perfectly controled priviledge control. If the trigger need to be changed, the signing process (including the cert derived login and grants) have to be done again. From a security point of view, this is desired (you are signing a specific variant of the trigger), from operational point of view is rather a pita, but is manageable.
create table t (i int);
create table audit (transaction_id int);
go
create trigger t_audit_trigger
on t
with execute as owner
after insert, update, delete
as
begin
set nocount on;
insert into audit (transaction_id)
select transaction_id from sys.dm_tran_current_transaction;
if (##ROWCOUNT != 1)
raiserror(N'Failed to audit transaction', 16, 1);
end
go
create certificate t_audit_view_server
encryption by password = 'Password#123'
with subject = N't_audit_view_server'
, start_date = '08/10/2009';
go
add signature to t_audit_trigger
by certificate t_audit_view_server
with password = 'Password#123';
go
alter certificate t_audit_view_server
remove private key;
backup certificate t_audit_view_server
to file = 'c:\temp\t_audit_view_server.cer';
go
use master;
go
create certificate t_audit_view_server
from file = 'c:\temp\t_audit_view_server.cer';
go
create login t_audit_view_server_login
from certificate t_audit_view_server;
go
grant authenticate server to t_audit_view_server_login;
grant view server state to t_audit_view_server_login;
go
From SQL Server 2008, Microsoft introduced sys.dm_exec_requests, which is to deprecate sys.sysprocesses. This view returns the transaction_id, and can be called without granting VIEW SERVER STATE. Like sys.sysprocesses, it returns details for the current process if VIEW SERVER STATE is not granted, and all processes if it is.
Although not directly answering your question, rather than using a custom built auditing framework, in SQL Server 2008 you could make use of the Change Data Capture Technology.
See the following reference from Books Online: http://msdn.microsoft.com/en-us/library/bb522489.aspx
EDIT (Solution, added): Here is a walkthrough of how to create a stored procedure to access the system view, making use of the execute as clause and using impersonation.
USE MASTER;
select * from sys.dm_tran_current_transaction
--Create a login with view server state permissions
CREATE LOGIN ViewServerStateLogin
WITH password = 'Hello123';
CREATE user ViewServerStateLogin;
--Create a login to test the permissions assignment
CREATE LOGIN TestViewServerState
WITH password = 'Hello123';
CREATE user TestViewServerState;
--Test with Login
EXECUTE AS LOGIN = 'TestViewServerState';
--This obviously does not work.
select * from sys.dm_tran_current_transaction
revert;
--Grant view server state permission to the ViewServerStateLogin
GRANT VIEW SERVER state TO ViewServerStateLogin;
--Create a procedure to wrap the call to the system view
CREATE PROCEDURE proc_TestViewServerState
AS
SET NOCOUNT ON;
EXECUTE AS LOGIN='ViewServerStateLogin'
select * from sys.dm_tran_current_transaction
revert;
RETURN(0);
--Assign execute permission to the test accounts
GRANT EXECUTE ON proc_TestViewServerState TO TestViewServerState
--Grant impersonation rights to the test login
GRANT IMPERSONATE ON LOGIN::ViewServerStateLogin TO TestViewServerState
--Test with Procedure
EXECUTE AS LOGIN = 'TestViewServerState';
EXEC proc_TestViewServerState
revert;
Starting with SQL Server 2016, you could use CURRENT_TRANSACTION_ID. According to the docs:
Any user can return the transaction ID of the current session.
Encrypt the stored procedure and don't share the pw for ViewServerStateLogin. Then you get a black box of sufficient density to satisfy the auditors.

Checking sp_send_email permission before executing

In my stored procedure, I send emails with sp_send_email. My stored procedure will be run in different environments; some will have emailing enabled, some won't.
If I run sp_send_email without it being enabled, I (quite rightly) get this error message
SQL Server blocked access to procedure 'dbo.sp_send_dbmail' of component 'Database Mail XPs' because this component is turned off as part of the security configuration for this server.
I want to check whether emailing is enabled first, so I can avoid the error by doing the following:
IF #is_enabled
BEGIN
EXEC sp_send_email ...
END
How do I correctly set #is_enabled?
You can query sys.configurations
IF EXISTS (SELECT *
FROM sys.configurations
WHERE name = 'Database Mail XPs' AND value_in_use = 1)
PRINT 'enabled'
ELSE
PRINT 'no luck'
The downside is that it may not be visible to non-sysadmin users because of "MetaData Visibility"
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Database Mail XPs';
GO
The sp_send_mail falls under the 'Database Mail XPs' umbrella. You application may not have the rights to run sp_configure and RECONFIGURE, so in the end you may be better if you simply try to invoke the sp_send_mail and handle the error.
BOL says:
To send Database mail, users must be a user in the msdb database and a member of the DatabaseMailUserRole database role in the msdb database. To add msdb users or groups to this role use SQL Server Management Studio or execute the following statement for the user or role that needs to send Database Mail.
So, you can give to user the appropriate role:
EXEC msdb.dbo.sp_addrolemember #rolename = 'DatabaseMailUserRole'
,#membername = '<user or role name>'; GO

Resources