User Granted Access to Stored Procedure but Can't Run Query - sql

I am working on a product that runs an SQL server which allows some applications to login and their logins are granted permission to run a stored procedure- AND NOTHING ELSE. The stored procedure is owned by an admin; the stored procedure takes a query and executes it, then the results are returned to the application.
Unfortunately I can't figure out why the application can call the stored procedure to which it's granted access, but the stored procedure cannot execute the SQL statement which was passed into it.
The stored procedure executes the passed in query when I'm logged in as an admin, but when I log in as the limited user it throws an exception in the execute statement.
For example:
EXEC [Admin].[STORED_PROC] #SQL_STATEMENT = 'SELECT * FROM table_x'
the STORED_PROC looks something like this:
BEGIN TRY
EXEC (#SQL_STATEMENT)
END TRY
BEGIN CATCH
-- some logging when an exception is caught, and the exception is caught here!!!
END CATCH
There is nothing inside the the try catch statement except that EXEC... and the SQL_STATEMENT works when I'm logged in as the Admin, but not when I'm logged in as the User.
Can anybody help me figure out what permissions I need to set in order to allow the User to run queries through the stored proc only?
So there have been some comments about allowing raw SQL statements to be executed via stored proc defeats the purpose of using a stored proc... but in reality what we're actually doing is we're passing an encrypted SQL statement into the stored proc and the stored proc gets the statement decrypted and THEN it executes it.
So yes, in reality raw SQL statements are not secure and they defeat the purpose of stored procs, but I don't know how to encrypt SQL queries that are passed through ODBC and run against a pre-2005 SQL Server.
In any case, I tried to put up some minimal safeguards to at least have some basic security.

Since you are using dynamic sql, SQL server can't tell which tables you are using, so you have to grant SELECT rights to all the tables as well

Users also need to have SELECT grant on the tables

Allowing raw SQL to be passed into a stored procedure and then executing is the very essence of data insecurity.
SQL Server security is structured so that arbitrary bits of SQL execute in their own security context. If you don't have the permission to run the query ad hoc, you also don't have the permission to run it through a stored procedure. In this, SQL Server is saving you from yourself.

Since your system allows access to stored procs and nothing else (which is good for security purposes and should not be changed) then you simply cannot under any circumstances use dynamic SQL because the rights are not at the table level and your dbas are unlikely to change that. This is not only to prevent SQL Injection attacks but to prevent possible internal fraud so any workplace which has considered this important will not be willing to compromise to make life easier for you. You simply need to redesign to never do anything dynamically. You have no other choice. If you write the procs to do what you want it to do in the first place, there is no need to send encypted sql.

When dynamic SQL is used through EXEC or sp_executesql within an SP, the EXEC permissions on the SP do not allow you to run arbitrary code in the dynamic sql. You either need to grant SELECT (yuck), or you might be able to impersonate another user using EXECUTE AS or SETUSER.
When normal SQL is used, EXEC permissions works fine, overridding ungranted SELECT persmissions. If you have DENY, though, I believe that trumps it.
Having said that, I'm still not sure you should use EXECUTE AS when the source of the SQL is outside the SP (or outside the database). For code-generation or dynamic sql which is safe from outside influence, EXECUTE AS can be a useful tool

This is most likely because of different schemas i.e. the user who logs in is not part of the Admin schema, or at least I would hope not.
The security technique that permits the type of access you are looking to achieve, i.e. to permit access to objects that are owned by the same schema, is called Ownership Chaining.
This principle is not best explained in a post.
Here is a link from Microsoft that explains the concept.
http://msdn.microsoft.com/en-us/library/ms188676(SQL.90).aspx
Here is a an outstanding article on security that provides examples and walkthroughs, for ownership chaining, amongst other techniques.
http://www.sommarskog.se/grantperm.html
I hope this is clear and assists you but please feel free to pose further questions.
Cheers, John

Related

Calling a series of stored procedures sequentially SQL

Is it possible (using only T-SQL no C# code) to write a stored procedure to execute a series of other stored procedures without passing them any parameters?
What I mean is that, for example, when I want to update a row in a table and that table has a lot of columns which are all required, I want to run the first stored procedure to check if the ID exists or not, if yes then I want to call the update stored procedure, pass the ID but (using the window that SQL Server manager shows after executing each stored procedure) get the rest of the values from the user.
When I'm using the EXEC command, I need to pass all the parameters, but is there any other way to call the stored procedure without passing those parameter? (easy to do in C# or VB, I mean just using SQL syntax)
I think you are asking "can you prompt for user input in a sql script?". No not really.
You could actually do it with seriously hack-laden calls to the Windows API. And it would almost certainly have serious security problems.
But just don't do this. Write a program in C#, VB, Access, Powerscript, Python or whatever makes you happy. Use an tool appropriate to the task.
-- ADDED
Just so you know how ugly this would be. Imagine using the Flash component as an ActiveX object and using Flash to collect input from the user -- now you are talking about the kind of hacking it would be. Writing CLR procs, etc. would be just as big of a hack.
You should be cringing right now. But it gets worse, if the TSQL is running on the sql server, it would likely prompt or crash on the the server console instead of running on your workstation. You should definitely be cringing buy now.
If you are coming from Oracle Accept, the equivalent in just not available in TSQL -- nor should it be, and may it never be.
Right after reading your comment now I can understand what you are trying to do. You want to make a call to procedure and then ask End User to pass values for Parameters.
This is a very very badddddddddddddddddddd approach, specially since you have mentioned you will be making changes to database with this SP.
You should get all the values from your End Users before you make a call to your database(execute procedure), Only then make a call to database you Open a transaction and Commit it or RollBack as soon as possible and get out of there. as it will be holding locks on your resources.
Imagine you make a call to database (execute sp) , sp goes ahead and opens a transaction and now wait for End user to pass values, and your end user decides to go away for a cig, this will leave your resources locked and you will have to go in and kill the process yourself in order to let other user to go and use database/rows.
Solution
At application level (C#,VB) get all the values from End users and only when you have all the required information, only then pass these values to sp , execute it and get out of there asap.
You can specify the parameters by prefixing the name of the parameter with the # sign. For example, you can call an SP like this:
EXEC MyProc #Param1='This is a test'
But, if you are asking if you can get away with NOT providing required parameters, the answer is NO. Required is required. You can make them optional by providing a default value in the declaration of the SP. Then you can either not pass the value or call it like this:
EXEC MyProc #Param1=DEFAULT
--OR
EXEC MyProc DEFAULT

Possible to create a SQL stored procedure for use for all databases

I have a stored procedure, in one database within my SQL server, that sets permissions to all stored procedures at once for that particulat database. Is there a way to create this stored procedure in a way were I can call it easily from any database within the SQL server and if so how do I go about doing such a thing
While the best solution to this specific question of granting execute to all procedures is the one provided by marc_s, the actual question was is there a way to create a single stored procedure and make it available to all databases.
The way to do this is documented at https://nickstips.wordpress.com/2010/10/18/sql-making-a-stored-procedure-available-to-all-databases/:
Create the stored procedure in the master database.
It must be named to start with sp_, e.g. sp_MyCustomProcedure
Execute sys.sp_MS_marksystemobject passing the name of the procedure, e.g. EXEC sys.sp_MS_marksystemobject sp_MyCustomProcedure
Here is a simple example which just selects the name of the current database:
use master
go
create procedure dbo.sp_SelectCurrentDatabaseName as begin
select db_name()
end
go
execute sys.sp_MS_marksystemobject sp_SelectCurrentDatabaseName
go
Calling exec dbo.sp_SelectCurrentDatabaseName on any database will then work.
To mark the procedure as not a system object, there a some nasty hacks suggested at https://social.msdn.microsoft.com/Forums/sqlserver/en-US/793d0add-6fd9-43ea-88aa-c0b3b89b8d70/how-do-i-undo-spmsmarksystemobject?forum=sqltools but it is safest and easiest to just drop and re-create the procedure.
Caveat
Of course creating system procedures like this is breaking the common rule of not naming your own procedures as sp_xxx, due to the possibility of them conflicting with built-in procedures in future versions of SQL Server. Therefore this should be done with care and not just create a load of randomly named procedures which you find useful.
A common simple way to avoid this is to add your own company/personal prefix to the procedure which Microsoft is unlikely to use, e.g. sp_MyCompany_MyCustomProcedure.
I have a stored procedure, in one database within my SQL server, that
sets permissions to all stored procedures at once for that particular
database.
You could archive the same result much easier:
create a new role, e.g. db_executor
CREATE ROLE db_executor
grant that role execute permissions without specifying any objects:
GRANT EXECUTE TO db_executor
This role now has execute permissions on all stored procedures and functions - and it will even get the same permissions for any future stored procedure that you add to your database!
Just assign this role to the users you need and you're done....
Have you tried a 3 or 4 part name?
InstanceName.DatabaseName.dbo.usp_Name
That procedure could in turn reference objects in other databases using the same conventions. So you could parameterize the name of the database to be operated on and use dynamic SQL to generate 4 part names to reference objects such as system tables.

permission problem on dynamic query running in a stored procedure

i have this stored procedure, doing a select query with couple of inner joins (one of the tables is in another db). Now, i had to write this query as dynamic cause first i had to find which db the select query should run. Anyway, none of the tables have permissions on them, just giving permission to the stored procedure for the database role "personel" (which includes everyone).
But now, someone with a personel role runs this stored proc, they are getting the error "The SELECT permission was denied on the object 'tbl_table', database 'Db', schema 'dbo'." no difference in the schema, and there are other procs using the same table that are running normally.
Can using a dynamic query (exec (Use DB; select ...) ) be the reason for this? Like cause it is dynamic, i should give permissions to the tables also ?
Thanks
The short answer is yes.
When you compile a stored procedure, permissions of the user/login creating the stored procedure are checked. When someone else executes it, their ability to read those tables is no longer relevant (in most cases), but rather just their ability to execute the SP.
When executing the dynamic code, however, the permissions regarding the tables have to be checked there and then. This means that the executing user's permissions are being checked.
Yes, this can be the reason. Read this to get an explanation and a possible solution.

Can I change execution context in a SP from OWNER to CALLER? [SQL Server 2005]

Is it possible to change execution context to CALLER in a stored procedure, which is created with EXECUTE AS OWNER? Here is what I mean with a simplified example:
There are several logins and databases in a server instance. Assume that everybody has a table named current_work in his own database, but nobody can access to no other's table. Even the Boss isn't allow to access to the employees' databases, unless an employer decides that his table is ready for the Boss to see. When the employer thinks his work is done, he is supposed to commit its table contents to Boss' database. However, the Boss doesn't want to allow his employers to INSERT anything into his table, because there is a kind of business logic he wants to implement (let's say he wants to log the commits somewhere). So he wants this to happen only under his control, i.e. within an SP he wrote. He writes an SP like below, creates users in his database for each of the logins (for each employee), and then gives GRANT EXECUTE for this SP to all his employers. When an employee is done, he just calls this SP, and everything should be fine:
CREATE PROCEDURE boss.dbo.commit_work
WITH EXECUTE AS OWNER AS
BEGIN
EXECUTE AS CALLER -- It should be OK, since this is the default way of calling an SP anyway, thinks the boss
SELECT * INTO ##tmptable FROM current_work -- No prefix should mean default DB/Schema of the caller, thinks the boss
REVERT -- Back to OWNER's context, which happens to be the boss
INSERT INTO boss.allwork
SELECT * FROM ##tmptable
END
However, things doesn't go as he expected. The employers can execute the SP, but they get an error saying 'The server principal "Boss" is not able to had access the database "boss" under the current security context.', which makes the boss very upset (BTW Boss is the Login for the boss.)
Do you have an idea of what went wrong? Or do you see another way of implementing such a scenario, in which nobody is supposed to access to no other's DB unless the execution happens in the SP? I would have done such a thing in application level, when I had had the choice, but I am bound to database level because of the requirements of our current environment. Thanks!
I found the answer here in this great article of Erlang Sommarskog "Giving Permissions through Stored Procedures". I recommend you to read the whole article to grasp the idea.. All I had to do was creating a local proxy user and giving it the appropriate rights:
CREATE USER boss_proxy WITHOUT LOGIN
GRANT INSERT ON boss.allwork TO boss_proxy
CREATE PROCEDURE boss.dbo.commit_work
WITH EXECUTE AS boss_proxy AS
BEGIN
EXECUTE AS CALLER -- It IS OK, indeed
SELECT * INTO ##tmptable FROM current_work -- No prefix means default DB/Schema of the caller
REVERT -- Back to boss_proxy's context
INSERT INTO boss.allwork
SELECT * FROM ##tmptable
END

SQL Server, Remote Stored Procedure, and DTC Transactions

Our organization has a lot of its essential data in a mainframe Adabas database. We have ODBC access to this data and from C# have queried/updated it successfully using ODBC/Natural "stored procedures".
What we'd like to be able to do now is to query a mainframe table from within SQL Server 2005 stored procs, dump the results into a table variable, massage it, and join the result with native SQL data as a result set.
The execution of the Natural proc from SQL works fine when we're just selecting it; however, when we insert the result into a table variable SQL seems to be starting a distributed transaction that in turn seems to be wreaking havoc with our connections.
Given that we're not performing updates, is it possible to turn off this DTC-escalation behavior?
Any tips on getting DTC set up properly to talk to DataDirect's (formerly Neon Systems) Shadow ODBC driver?
Check out SET REMOTE_PROC_TRANSACTIONS OFF which should disable it.
Or sp_serveroption to configure the linked server generally, not per batch.
Because you are writing on the MS SQL side, you start a transaction.
By default, it escalates whether it needs to or not.
Even though the table variable does not particapate in the transaction.
I've had similar issues before where the MS SQL side behaves differently based on if MS SQL writes, in a stored proc and other stuff. The most reliable way I found was to use dynamic SQL calls to my Sybase linked server...
The following code sets the "Enable Promotion of Distributed Transactions" for linked servers:
USE [master]
GO
EXEC master.dbo.sp_serveroption #server=N'REMOTE_SERVER', #optname=N'remote proc transaction promotion', #optvalue=N'false'
GO
This will allow you to insert the results of a linked server stored procedure call into a table variable.
I'm not sure about DTC, but DTSX (Integration Services) may be useful for moving the data. However, if you can simply query the data, you may want to look at adding a linked server for direct access. You could then just write a simple query to populate your table based on a select from the linked server's table.
That's true. As you might guess, the Natural procedures we want to call do lookups and calculations that we'd like to keep at that level if possible.