How to set up access to MSSQL 2005 Database Mail? - sql-server

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

Related

SQL xp_create_subdir for non-admin

I'd like to give a non-admin the ability to create folders on the SQL server's local hard disk using xp_create_subdir. Reason - need to create a folder structure so that manufacturing equipment can FTP large files. Meta data for the files is stored in SQL.
Server is SQL 2016 Express. OS is Windows 10 Pro.
I've found lots of explanations of how to get this to work but can't figure out what I'm missing. Using the SA account I've created a stored procedure like this:
use [DBname]
CREATE PROCEDURE dbo.usp_CreateDirectory
#directoryFullPath varchar(500)
WITH EXECUTE AS owner
AS
BEGIN
SET NOCOUNT ON;
EXEC master.dbo.xp_create_subdir #directoryFullPath;
END
GO
GRANT EXECUTE ON dbo.usp_CreateDirectory TO [TestUser]
GO
Code to run the stored procedure:
DECLARE #RC int
DECLARE #directoryFullPath varchar(500)
set #directoryFullPath = 'd:\FTP_Root\2020\08\22\'
EXECUTE #RC = dbo.usp_CreateDirectory
#directoryFullPath
GO
In Windows I've given NT Service\MSSQL${InstanceName} full access to d:\FTP_Root\
What am I missing? Running xp_create_subdir 'C:\FTP_Root\2020\08\22' in MSSMS works fine.
Running the stored procedure as SA or the non-admin TestUser gives this result:
Msg 229, Level 14, State 5, Procedure xp_create_subdir, Line 1 [Batch
Start Line 2] The EXECUTE permission was denied on the object
'xp_create_subdir', database 'mssqlsystemresource', schema 'sys'.
I found this on another site: https://www.sqlservercentral.com/forums/topic/xp_create_subdir-for-non-sysadmins
The headlines here are two main points
Although this post is old,
In order to solve this issue, you should make sure that your database is Trustworthy - since the SP xp_create_subdir is on different DB
You still need to set "with Execute as 'dbo'
alter database [DBNAME] set trustworthy on
- Guy-456224
And DO understand the security ramifications of using SET TRUSTWORTHY ON. It may not be a problem or... it may. "It Depends" but you won't know until you read about it.
- Jeff Moden
I completely agree with Jeff on this one. If you remotely care about security, understand what the TRUSTWORTHY setting does before adjusting it.
I think the larger question here is to ask why SQL Server needs to create the directory? Powershell could both query the database for the Directory Path and create the Directory. You could have a SQL Server Agent job that will execute this under the security context of either a SQL Server Proxy account, or the SQL Agent service account (I would pick the proxy account personally, but that's just me).

SSRS call to stored procedure fails, Cannot find user 'dbo'

I've got a SSRS report that is calling a stored procedure in my database.
Locally everything works, I am connecting with Windows authentication locally to hit the database and there are no problems.
When the SSRS report is deployed it's set up to use a different login, and this login has the correct role to grant execute on stored procedures. However, when trying to view the report on SSRS server I get this message:
Cannot find the user 'dbo', because it does not exist or you do not have permission.
If I remove the role that allows the grant execute rights I get a more specific error saying that I don't have permission to execute the stored procedure. But once this role is put back on the user account SSRS runs as it goes back go showing an error
Cannot find the user 'dbo'
The role I have that is granted execute rights is granted by 'dbo' user, this is the database owner. I have found things online saying that it's possible that a database backup messed up some user logins. I have checked, and the database owner sid is the same as the sysuser sid for name = 'dbo', so I do not think this is the problem.
Does anyone else know what I might be able to try?
EDIT: Details on stored procedure: it is a simple select with some inner joins.
At the end of the stored procedure is the following, granting access to the role my SSRS user is part of:
GRANT EXECUTE
ON OBJECT::[dbo].[Application_LoadData] TO [SSRSUserRole]
AS [dbo];
A stored procedure includes all statements in the batch after the CREATE PROCEDURE. So a proc like this
CREATE PROCEDURE USP_FOO
AS
BEGIN
SELECT * FROM FOO
END
GRANT EXECUTE ON USP_FOO TO SOMEUSER AS DBO;
Will attempt to execute to GRANT every time the procedure is run, and will fail when not run by dbo.
The script to create the procedure should have a batch separator before the grant. eg:
CREATE PROCEDURE USP_FOO
AS
BEGIN
SELECT * FROM FOO
END
GO
GRANT EXECUTE ON USP_FOO TO SOMEUSER AS DBO;

How to create a login that ONLY has access to run stored procedures?

I have a C# Winform application that interacts with an SQL Server DB via stored procedures. In SSMS, how do I create a login that ONLY has permissions to run stored procedures? That login wouldn't be able to view/edit/create table definitions, etc. It would also only have access to a single specified DB.
The reason I want to create such a login is because I store the SQL Server credentials used by my Winform application in its App.config file. Since the app.config can easily be read, anyone with malicious intent can easily perform unwanted operations on the database if the given login had any other permissions than just stored procedures.
A neat trick in this scenario is to create a separate (custom) SQL Server role that can only execute stored procedures:
CREATE ROLE db_executor;
GRANT EXECUTE TO db_executor;
This role now has the permission to execute any stored procedure in the database in which it's been created - and in addition: that permission will also extend to any future stored procedures you might create later on in this database.
Now create a user in your database and give it only this database role - this user will only be able to execute stored procedures - any and all of them in your database.
If you user should be allowed to execute any and all stored procedures - this is a very convenient way to allow this (and you don't have to constantly update the permissions when new stored procedures are created).
You can use the following query in order to allow stored procedure execute permision to your user
USE [DB]
GRANT EXECUTE ON dbo.procname TO username;
However, in my humble opinion , you should secure the connection string in the app.config.
Maybe , this How to store login details securely in the application config file link can be helped to you.
The access to a specific database is done through creating a user on the database that you want him to operate on. You can find more infos about users here.
If the user is created you can Grant, With Grant and Deny actions for every single item on the database.
The user will then be granted/denied those rights by a grantor, which is the dbo by default.
You can use this to also deny him access to every item on your database that isn't your stored procedure, which is what you're looking for if I understand you correctly.
Try folloiwng approach (grant execute should be repeated for every SP). Note that MyStoredProcedure has to be in MyDatabase :)
-- create login to server
create login test_user with password = 'test';
-- create user mapped to a database
use MyDatabase
go
create user test_user for login test_user;
-- grant permission to execute SP
grant execute on MyStoredProcedure to test_user

create proc with exec as 'dbo' not working crossing databases?

There is a stored procedure
use db1
go
create proc SP1
-- with execute as 'dbo'
as
-- complex code omitted for the question
exec db2.SP2
-- calls other stored procs of other databases too
UserA has only permission to exec db1.dbo.SP1 and it got an error of no permission to exec db2.SP2 and got the following error.
The server principal "Domain\UserA" is not able to access teh database "db2" under the current security context.
I uncommented the line -- with execute as 'dbo' and the error message changed to
The server principal "Domain\DBA" is not able to access teh database "db2" under the current security context.
DBA is sysadmin and it's associate to dbo. It should have all the permissions?

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