I want to know what are the default permissions for sql server stored procedures.
For example, I created a user in database but no role or no permissions granted except execute permission like:
GRANT EXECUTE ON SCHEMA :: [dbo] TO [newUser]
later on me (as a sa login) created a stored procedure that makes just a select from a table like:
CREATE PROCEDURE dbo.selectX AS
BEGIN
SELECT ID, NAME FROM MyTable
END
and my user [newUser] can execute and see the result of select statement like:
EXEC dbo.selectX
up until now, I can assume that stored procedures have default permissions that my user don't have.
I tried other dmls like UPDATE, INSERT, DELETE and user managed to execute procedures successfully.
But! when I created a proceure with ddl as create table .. such as:
CREATE PROCEDURE dbo.crtNT AS
BEGIN
CREATE TABLE del(id int) --for test
END
and when the newUser executes this procedure error occurs like:
CREATE TABLE permission denied in database 'MyDb'
And here is my question: By default, do stored procedures have permission with DML(select, insert, update vs.) but not with DDL(create, drop table vs.)? Because I didn't see any explanation about this situation in Books Online or anywhere else.
Any comments will be welcomed.
You are correct in your assumption that DDL statements are treated differently.
The procedures with DML statements work through the mechanism of Ownership Chaining however as this quote from the EXECUTE AS documentation states
Remember that ownership chaining applies only to DML statements.
Related
I'm trying to figure out if there is a way to achieve the converse of this:
can a SQL Server stored proc execute with higher permission than its caller?
I want to create a stored procedure which does one thing if the user is in a role, but a fallback option if they're not.
My first attempt tried to query the current user's roles, based on this:
How to query current user's roles
I tried to query what role a user was in, and decide what to do based on that. But if you set "mydomain\Domain Users" to a role (for example), users who belong to Domain Users aren't listed in the sys.database_role_members view. So users who were supposed to have permissions don't.
From here https://msdn.microsoft.com/en-us/library/ee677633.aspx
IS_ROLEMEMBER always returns 0 when a Windows group is used as the database
principal argument, and this Windows group is a member of another Windows
group which is, in turn, a member of the specified database role.
My next attempt works like this. Create a stored procedure with the actual permissions, and then a wrapper around it which calls the with lower permissions, and if that fails, perform the fallback action:
CREATE PROCEDURE [internal_myproc]
AS
BEGIN
-- do something here
END
GO
GRANT EXECUTE ON [internal_myproc] TO [Role1] AS [dbo]
GO
CREATE PROCEDURE [myproc]
AS
BEGIN
BEGIN TRY
EXEC [internal_myproc]
END TRY
BEGIN CATCH
-- perform fallback action
END CATCH
END
GO
GRANT EXECUTE ON [internal_myproc] TO [Role1] AS [dbo]
GO
GRANT EXECUTE ON [internal_myproc] TO [Role2] AS [dbo]
GO
GRANT EXECUTE ON [internal_myproc] TO [Role3] AS [dbo]
GO
The problem with this is that [Role1] and [Role2] both succeed in executing [internal_myproc] via [myproc]. If you take the code out of the stored procedure, it behaves the way it should, but because it's hidden inside a stored procedure, it gets implicit permissions to execute other stored procedures. I've experimented with "WITH EXECUTE AS" stuff, but it doesn't seem to change anything.
I also tried "IF HAS_PERMS_BY_NAME('internal_myproc', 'OBJECT', 'EXECUTE') = 1", suggested here MS SQL Server: Check to see if a user can execute a stored procedure , but that seems to not work in certain situations I haven't understood yet.
Is there a way to NOT grant those implicit permissions, to do a permission check inside a stored procedure? Or something equivalent?
If you run the following in sql server...
CREATE SCHEMA [cp]
GO
CREATE TABLE [cp].[TestIt](
[ID] [int] NULL
) ON [PRIMARY]
GO
CREATE PROCEDURE cp.ProcSub
AS
BEGIN
Print 'Proc Sub'
END
GO
CREATE PROCEDURE cp.ProcMain
AS
BEGIN
Print 'Proc Main'
EXEC ProcSub
END
GO
CREATE PROCEDURE cp.ProcMain2
AS
BEGIN
Print 'Proc Main2'
SELECT * FROM TestIt
END
GO
exec cp.ProcMain2
GO
exec cp.ProcMain
GO
You get the error
Could not find stored procedure 'ProcSub'
Which makes it impossible to compartmentalize procedures into a schema without hard coding the schema into the execution call. Is this by design or a bug as doing a select on tables looks in the procedures schema first.
If anyone has a work around I'd be interested to hear it, although the idea is that I can give a developer two stored procedures which call each other and can put into whatever schema they like in 'their' database that they can run for the purpose of being a utility that looks at the objects of another given schema in the same database.
I have looked to see if I might be able to get round it with Synonyms but they seem to have the same problem associated with them.
This is by design, because the default schema is not set for the user calling the procedure.
When schema is not specified in the query, sql server will try the default schema first and then the dbo (if different) schema. So you need to set the default schema or make your procedure creation using fully qualified names.
Check out:
Beginning with SQL Server 2005, each user has a default schema. The
default schema can be set and changed by using the DEFAULT_SCHEMA
option of CREATE USER or ALTER USER. If DEFAULT_SCHEMA is left
undefined, the database user will have dbo as its default schema.
https://technet.microsoft.com/en-us/library/ms190387%28v=sql.105%29.aspx
Let's say that in a multi-schema db we have these 2 procs:
Create proc S1004.proc1
As
Exec proc2
GO
Create proc S1004.proc2
As
Select 1
Then, when I try to run proc1 from sa login, sql issues an error : Could not find stored procedure 'proc2'.
I know that if we add schema to proc2 in the body of proc1, then it can resolve the schema.
Is there any other solution for this problem.
If you can use your schema in the 'scope' of user (be aware that users and schemas are separated in SQL Server), you could get away with this:
CREATE USER S1004 FOR LOGIN S1004 WITH DEFAULT_SCHEMA = S1004;
GO
CREATE PROCEDURE S1004.proc1
WITH EXECUTE AS 'S1004'
AS
EXECUTE proc2
GO
CREATE PROCEDURE S1004.proc2
AS
SELECT 1
EXEC S1004.proc1
What happens here is that you create user S1004 with a default schema with the same name. That schema will be searched for object when object is not found immediately in the scope of current schema.
When you need to resolve your schema in a procedure, you run the procedure in the context of that user (see WITH EXECUTE AS 'S1004') and schema resolution will succeed.
However, pay attention that this changes execution scope to the another user. It's a workaround, but under the circumstances it's the best you can get.
In my SQL Server 2005 database, a user belongs to a role and that role has been granted execute permission on all the stored procedures. One of the stored procedures inserts data into the table called tableA.
User has been explicit DENY permission on tableA. However, user can still execute stored procedure to insert new data.
Is there a way to prevent user to insert new data into the table (besides removing user from the role which has execute permission)
create table tableA
(id int identity(1,1), data varchar(20)
)
create proc uspInsertTableA
(#data varchar(20))
with execute as caller
as
begin
insert into tableA
values (#data)
end
DENY INSERT On tableA TO BrianG
GRANT EXECUTE on uspInsertTableA to BrianG
BrianG, can still insert data
exec uspInsertTableA 'yada'
There are two relevant factors:
"execute as" of the stored procedure.
Ownership chaining.
"EXECUTE as CALLER" is already the default (CREATE PROCEDURE ... WITH EXECUTE AS CALLER ...)
Additionally the stored procedure must have a different owner than TableA, to prevent ownership chaining. The owner of the stored procedure must not have the right to insert into the table.
Alternatively you could use the HAS_PERMS_BY_NAME function within the stored procedure to explicitly check whether the user has the permission.
if HAS_PERMS_BY_NAME('TableA','OBJECT','INSERT') = 0
raiserror ('User is not allowed to insert into TableA',16,1)
Could you change the database schema of the sproc? ie. change from dbo.Insert to protected.Insert?
Then you could deny exec against this schema?
I have a SQL Server 2008 database where all access to the underlying tables is done through stored procedures. Some stored procedures simply SELECT records from the tables while others UPDATE, INSERT, and DELETE.
If a stored procedure UPDATES a table does the user executing the stored procedure also need UPDATE permissions to the affected tables or is the fact that they have EXECUTE permissions to the stored procedure enough?
Basically I am wondering if giving the user EXECUTE permissions to the stored procedures is enough or do I need to give them SELECT, UPDATE, DELETE, and INSERT permissions to the tables in order for the stored procedures to work. Thank you.
[EDIT] In most of my stored procedures it does indeed appear that EXECUTE is enough. However, I did find that in stored procedures where "Execute sp_Executesql" was used that EXECUTE was not enough. The tables involved needed to have permissions for the actions being performed within "sp_Executesql".
Permissions on tables are not checked (including DENY) if tables and proc have the same owner. They can be in different schemas too as long as the schemas have the same owner.
See Ownership chaining on MSDN
Edit, from a comment from a deleted answer.
The context is always the current login unless EXECUTE AS as been used: only referenced object DML permissions are not checked. Try OBJECT_ID(referencedtable) in a stored proc where no rights are assigned to referencedtable. It gives NULL. If executed by the owner of the stored proc then it would give a value because owener has rights on referencedtable
Execute permissions on the stored procedure is sufficient.
CREATE TABLE dbo.Temp(n int)
GO
DENY INSERT ON dbo.Temp TO <your role>
GO
CREATE PROCEDURE dbo.SPTemp(#Int int)
AS
INSERT dbo.Temp
SELECT #Int
GO
GRANT EXEC ON dbo.SPTemp TO <your role>
GO
Then the (non-db_owner) user will have the following rights:
EXEC dbo.SPTemp 10
GO
INSERT dbo.Temp --INSERT permission was denied on the object 'Temp'
SELECT 10
However, if there is dynamic SQL inside dbo.SPTemp that attempts to insert into dbo.Temp then that will fail. In this case direct permission on the table will need to be granted.
Maybe you can use
"with execute as owner"
when you create the stored procedure, such as below:
create procedure XXX
with execute as owner
as
begin
...
end
go
Then you only need to grant the user the EXECUTE permission for the stored procedure XXX.
Execute permission on a stored procedure that does an insert, update, or delete is sufficient. You do not need to grant those permissions at the table level. In fact, I would discourage that approach. Using a stored procedure gives you more control over how the change occurs. For instance, you may wish to do some checking prior to allowing the update. Using a stored procedure can also help prevent major accidents--like deleting all the rows in the table because someone forgot the WHERE clause!
THANK YOU SO MUCH! I had a similar problem. This lead me to the answer.
I was attempting to trunctate a table in a stored procedure that called other stored procedures that were nested in IF statements.
My error was
The server principal "domain\my_id" is not able to access the database "2nd_DB" under the current security context.
I had given the calling stored procedure rights to do the truncate (EXECUTE AS SELF), which then caused a problem because SELF didn't have rights to the 2nd DB. Our solution was to move the truncate to another SP, include the EXECUTE AS SELF. We now call the truncate SP, execute our data processing, make logic determination, and call the appropriate 3rd SP.