Checking sp_send_email permission before executing - sql-server

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

Related

SQL proxy account credentials Error code - 0, Status code - 0

I want to create a proxy user that will be able to run xp_cmdshell tasks like an administrator user does.
Note: I don't want to give this new user sysadmin permissions!
When I login from administrator, I can create the credentials for the proxy user and when I run select * From sys.credentials I can see the created credential there but when I try to run a simple xp_cmdshell task from the testuser like EXECUTE MASTER ..XP_CMDSHELL 'echo HI'
it gives an error like:
The server principal "testuser" is not able to access the database "master" under the current security context.
From the administrator side I tried:
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
GRANT EXECUTE ON xp_cmdshell TO [testuser]
create credential xp_cmdshell_proxy_account with identity = 'test\testuser', secret = 'test123'
When I run all these statements they all give me a successful response but if I try to run the credential like : EXEC sp_xp_cmdshell_proxy_account 'test\testuser','test123';
I get an error saying:
An error occurred during the execution of sp_xp_cmdshell_proxy_account. Possible reasons: the provided account was invalid or the '##xp_cmdshell_proxy_account##' credential could not be created. Error code: 0(null), Error Status: 0.
Can you help me and tell me what I am missing here?

Check if a user can run the RECONFIGURE statement

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;

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.

sql server sp_send_dbmail

I am using SQL Server's sp_send_dbmail stored procedure to send mail via the database.
But when I execute that procedure it's shutting down the db mail procedure. I tried to start it again by sysmail_start_sp. But it's again shutting down in 7-8 seconds.
I tried with the code below:
EXEC msdb..sp_send_dbmail #profile_name = 'Test',
#recipients = 'abc#gmail.com',
#subject = 'test mail',
#body_format = 'HTML',
#body = 'test mail',
#from_address = 'xyz#yahoo.com'
When I tried to check the error log I found the below error:
Message:
The read on the database failed. Reason: The error description is
'Whitespace is not allowed at this location.'.Data:
System.Collections.ListDictionaryInternalTargetSite:
Microsoft.SqlServer.Management.SqlIMail.Server.Objects.QueueItem
GetQueueItemFromCommand(System.Data.SqlClient.SqlCommand)HelpLink:
NULLSource: DatabaseMailEngineStackTrace
Information===================
Also when I checked sql email log history I found this error:
Mail not queued. Database Mail is stopped. Use sysmail_start_sp to start Database
Mail.
Whenever you try to send Test mail from Database mail; it throws below error message:
Msg 14641, Level 16, State 1, Procedure sp_send_dbmail, Mail not
queued. Database Mail is stopped. Use sysmail_start_sp to start
Database Mail.
First of all make sure that Service Broker Message Delivery in Databases is enabled by executing the following command in SSMS:
SELECT is_broker_enabled FROM sys.databases WHERE name = 'msdb'
If the result of above query is 0, then activate the service broker.
Activating Service Broker allows messages to be delivered to the database. A Service Broker endpoint must be created to send and receive messages from outside of the instance.
To activate Service Broker in a database use the following command:
USE master ;
GO
ALTER DATABASE DatabaseName SET ENABLE_BROKER ;
GO
If the Service Broker is enabled then confirm whether Database Mail is enabled or not by executing below queries in SQL Server Management Studio:
sp_configure 'show advanced', 1
GO
RECONFIGURE
GO
sp_configure
GO
If the result set shows run_value as 1 then Database Mail is enabled.
If the Database Mail option is disabled then run the below queries to enable it:
sp_configure 'Database Mail XPs', 1;
GO
RECONFIGURE;
GO
sp_configure 'show advanced', 0;
GO
RECONFIGURE;
GO
Once the Database Mail is enabled then to start Database Mail External Program use the below mentioned query on msdb database:
USE msdb ;
EXEC msdb.dbo.sysmail_start_sp;
To confirm that Database Mail External Program is started, run the query mentioned below :
EXEC msdb.dbo.sysmail_help_status_sp;
If the Database Mail external program is started then check the status of mail queue using below statement:
EXEC msdb.dbo.sysmail_help_queue_sp #queue_type = 'mail';
There are few things to troubleshoot, firstly check to make sure database Mail is enabled by executing the following
SELECT is_broker_enabled FROM sys.databases WHERE name = 'msdb'
If the result of above is 0, activate the service broker by following this guide
If the result of above is 1, then check the status of Database Mail, execute the following statement:
EXECUTE dbo.sysmail_help_status_sp
To start Database Mail in a mail host database, run the following command in the msdb database:
EXECUTE dbo.sysmail_start_sp

How to set up access to MSSQL 2005 Database Mail?

I've just setup Database mail within MSSQL 2005. I have been able to send email from an administrator account on the server and through a SQL Server Agent job. But, I unable to send email when I tried to send email via a login that just has access to a database for our web application.
What is the best way to set up access to Database Mail?
I have 2 senerios where I want to send email.
Schedule a job through SQL Server Agent to run a Stored Procedure that does some process and then sends an email. (this hasn't been a problem)
Have a stored procedure invoked from a web application that calls another stored procedure which could send an email. (this is were my permissions issue is)
Possible Solutions
The only way that I have found to grant permission to a login is to map the login to the msdb database and grant the public and DatabaseMailUserRole. This really concerns me as I would assume that this gives to much access to the msdb database.
Store the email I want to send in a table and then have a SQL Server Agent job look at that table every so often to send any queued emails. This way the database login for the web application does not execute the [msdb].[dbo].[sp_ send _dbmail] call and thus does not need any permission to the msdb database.
Are there any other solutions?
You should be able to create a stored procedure WITH EXECUTE AS OWNER option so it runs in the context of the owner rather than the caller.
CREATE PROCEDURE [dbo].[sp_SendMail]
(
#To nvarchar(1000),
#Subject nvarchar(100),
#Body nvarchar(max)
)
WITH EXECUTE AS OWNER
AS
BEGIN
exec msdb.dbo.sp_send_dbmail #profile_name = 'MailProfile',
#recipients = #To,
#subject = #Subject,
#body = #Body
END
I'm trying to do the same but executing
GRANT EXECUTE ON dbo.sp_SendMail TO User1
is not fixing this issue. Only thing which is making this procedure to work is not adding
EXECUTE AS OWNER
(I'm creating it with "WITH ENCRYPTION" only) and adding user which will be running this procedure to msdb DatabaseMailUserRole role:
USE msdb
GO
EXEC sp_adduser #loginame='USERNAME', #grpname='DatabaseMailUserRole'
GO
Thanks

Resources