Permissions to set job Enable/Disable in SQL Server - sql-server

The database user has been granted SQLAgentOperatorRole, but there are still error when set job enable/disable. The error message is:
SELECT permission was denied on the object 'sysjobs', database 'msdb', schema 'dbo'
We set the job enable/disable by sp_update_job.
Comments:
When executing the following statement, will get the error.
bool result = ObjectInstance.ExecuteStoreQuery<bool>("EXEC usp_prod_SetJobStatus #jobName={0}, #isEnable={1}", jobName, isEnable).FirstOrDefault();
But, while use the following statement, it will execute successful.
ObjectInstance.ExecuteStoreCommand("EXEC msdb.dbo.sp_update_job #job_name={0}, #enabled={1}", jobName, isEnable);
usp_prod_SetJobStatus SP:
CREATE PROCEDURE [dbo].[usp_prod_SetJobStatus]
#jobName VARCHAR(200),
#isEnable BIT
AS
BEGIN
DECLARE #jobId uniqueidentifier
DECLARE #result BIT
SELECT #jobId = job_id FROM msdb.dbo.sysjobs WHERE name = #jobName
IF(#jobId IS NOT NULL)
BEGIN
EXEC #result = msdb.dbo.sp_update_job #job_name=#jobName, #enabled=#isEnable
END
ELSE
BEGIN
SET #result = 1
END
SELECT #result
END

I have solved this problem. The reason is that there is no SELECT permission on sysjobs table for the user. So, we need to grant the SELECT perssion for the user.
USE msdb
GRANT SELECT ON msdb.dbo.sysjobs TO useName

You have given agent operator role its having enable and disable but SQLAgentOperatorRole members can enable or disable local jobs they do not own by using the stored procedure sp_update_job and specifying values for the #enabled and the #job_id (or #job_name) parameters. If a member of this role specifies any other parameters for this stored procedure, execution of the procedure will fail ..You have to execute permissions on sql server agnet .

Related

SQL Server returns error with sp_trace_generateevent

I get an error from one of my databases when trying to execute this one
create or alter procedure [dbo].[test_sp]
with execute as owner
as
SELECT SUSER_SNAME()+ ' '+ USER_NAME();
begin
exec master..sp_trace_generateevent #eventid = 82 ,
#userinfo=N'test'
end
GO
exec [dbo].[test_sp]
Error:
Msg 8189, Level 14, State 10, Procedure master..sp_trace_generateevent, Line 1 [Batch Start Line 9]
You do not have permission to run 'SP_TRACE_GENERATEEVENT'.
Granted ALTER TRACE to my user (which returns in SUSER_SNAME()), but it wasn't help
The same script on the second database (same server) works without errors.
What else can it be?
You're trying to run this with EXECUTE AS OWNER, and the owner is a database-level principal and you can't operate outside the current database while impersonating a database-level principal. Switch to EXECUTE AS CALLER (the default) to have the caller's identity used to run the proc in master. eg
create or alter procedure [dbo].[test_sp]
with execute as caller
as
SELECT SUSER_SNAME()+ ' '+ USER_NAME();
begin
exec master..sp_trace_generateevent #eventid = 82, #userinfo = N'test'
end
GO
exec [dbo].[test_sp]
This can be made to work with owner-impersonation by marking the database as TRUSTWORTHY. See: Extending Database Impersonation by Using EXECUTE AS and Guidelines for using the TRUSTWORTHY database setting in SQL Server

Grant Server roles SQL server 2008R2

I have a tool which updates my sql table 'eptrack' with the following information
Server, Instance, userid, access, startdate and expirydate.
every time this table is updated a trigger will initiate a job which in turn connects to the respective server/Instance and grant the requested server roles.
I am able to grant the role via the following query.
exec sp_addsrvrolemember'na\admin_Test1', 'sysadmin'
However when i try to pick this info from the table via the below query,I get an error.
EXEC sp_addrolemember '(select userid from eptrack)' , '(select access from eptrack)'
Could I get a help for a query on granting the server role picked from the table for the userid in the same table
According to sp_addrolemember,this accepts variables as well
-- Syntax for SQL Server and Azure SQL Database
sp_addrolemember [ #rolename = ] 'role',
[ #membername = ] 'security_account'
so you can try something like below
declare #rolename sysname,
#membername sysname
select #rolename='db_Datareader',#membername='test'
EXEC sp_addrolemember #rolename,#membername
The above select can be from your table,if there are multiple results from select this will not work as expected, you may want to have a method which tracks/get only one row at a time
You should use a cursor for going through your table, get 1 row at a time, assign 2 variables and pass them to sp_addsrvrolemember like this:
declare #eptrack table (userid sysname, access sysname);
insert into #eptrack values ('na\admin_Test1', 'sysadmin');
declare #rolename sysname, #membername sysname;
select #rolename = access, #membername = userid
from #eptrack;
exec sp_addsrvrolemember #membername, #rolename;
Thank you for the assistance. I tried the above query as mentioned below
declare #rolename sysname,
#membername sysname
select #rolename=(select access from eptrack),#membername= (select userid from eptrack)
EXEC sp_addrolemember #rolename,#membername
I see an error the user id does not exist. I just inserted the information in the table and executed the query after that.
This worked, thank you. however we are entering the userid and access manually and we need those info picked from the table
declare #eptrack table (userid sysname, access sysname);
insert into #eptrack values ((select userid from eptrack), (select access from eptrack));
declare #rolename sysname, #membername sysname;
select #rolename = access, #membername = userid
from #eptrack;
exec sp_addsrvrolemember #membername, #rolename;
I tried the above one and see an error user id is not a valid login.
wanted to check if I am entering the select command right?
The table will have new rows inserted frequently and the query needs to pick the userid and access from the table every time a new value is inserted.

MSSQL trigger will not work with stored procedure

My code is to have a trigger that recognize when a job failed, sends an email and update our ticketing system using a stored procedure that is in a linked db.
The emailing part works perfect, but when adding the ticket procedure code the email wont send, the ticket will not open, and the specific line that was supposed to be in msdb.dbo.sysjobhistory is actually missing, like the insert failed or the line was deleted.
The procedure code line by itself works fine, and if i run the same code without the trigger part it also works fine.
The code works ok outside of the trigger, which makes me think I missing something regarding the way triggers work.
alter TRIGGER trig_open_ticket_failed
ON msdb.dbo.sysjobhistory
after INSERT
AS begin
DECLARE #MaxInstance int
Declare #failedFlag int
Declare #JobName varchar(50)
Declare #ErrorInfo varchar(max)
Declare #stepName varchar(50)
set #MaxInstance= (select MAX(instance_id)
from msdb.dbo.sysjobhistory
)
select top 1 #failedFlag = hs.run_status, #stepName=hs.step_name
from msdb.dbo.sysjobhistory hs join msdb.dbo.sysjobs sj
on hs.job_id=sj.job_id
where instance_id= #MaxInstance
if #failedFlag=0
BEGIN
SELECT TOP 1 #JobName= 'LKSQL job failed:' + SJ.name, #ErrorInfo=hs.message
from msdb.dbo.sysjobhistory hs join msdb.dbo.sysjobs sj
on hs.job_id=sj.job_id
where instance_id= #MaxInstance
set #errorInfo= 'Job: '+ #JobName +' Failed with error: '+ #errorInfo;
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'name',
#recipients = 'adrs#email.com',
#body = #ErrorInfo,
#subject = #JobName ;
exec [mainsql01].[SlickTicket].[dbo].[AddTicket] 'servicesFailed',#jobName, #ErrorInfo, '5','4' ;
END
end
GO
Thank you,
Idan.
your trigger will be executing as caller by default,which I am guessing does not have permission to use your addticket procedure. try adding
execute as user_name
where user_name has permission to use that proc

sys.database_principals is not executed in current database if called from sp procedure (stored in master)

I would like to print out database users of an actual database in a SP procedure (see the code of sp_PrintUsers below), however, for some reason it print out database users of master. It seems that it is a general behavior of SP procedure for all database-level views despite the fact that any database-level SQL statement is executed in the actual database. If we print out the DB_NAME that it is clearly not master, so what is wrong?
Is there any workaround?
use [master]
go
create procedure sp_PrintUsers
as
begin
SELECT DB_NAME() AS DataBaseName
select name from sys.database_principals;
end
go
use [actual_database]
go
exec sp_PrintUsers
Try executing the select dynamically as in:
EXEC('select name from sys.database_principals;');
If that does not help build the query to reference the catalog view with a three part name.
Try this :
use [master]
go
create procedure sp_PrintUsers
as
begin
declare #dbname varchar(30) = DB_NAME()
EXEC ('select name from ' + #dbname + '.sys.database_principals');
end
go
use [actual_database]
go
exec sp_PrintUsers

SQL Server 2008 insert trigger not firing

I have an INSERT trigger on a table that simply executes a job.
Example:
CREATE TABLE test
(
RunDate smalldatetime
)
CREATE TRIGGER StartJob ON test
AFTER INSERT
AS
EXEC msdb.dbo.sp_start_job 'TestJob'
When I insert a record to this table, the job is fired of without any issue. There are a few people, however, that have lower permissions than I do (db_datareader/db_datawriter on the database only); they are able to insert a record to the table, but the trigger does not fire.
I am a SQL Server novice and I was under the impression that users did not need elevated permissions to fire off a trigger (I thought that was one of the big benefits!). Is this a permission issue at the trigger level, or at the job level? What can I do to get around this limitation?
The trigger will execute in the context of the caller, which may or may not have the permissions to access msdb. That seems to be your problem. There are a few ways to extend these permissions using Execute As; they are greatly detailed in this link
Use impersonation within trigger:
CREATE TRIGGER StartJob ON test
with execute as owner
AFTER INSERT
AS
EXEC msdb.dbo.sp_start_job 'TestJob'
And set database to trustworthy (or read about signing in above link):
alter database TestDB set trustworthy on
Another way to go (depending on what operations the agent job performs) would be to leverage a Service Broker queue to handle the stored procedure activation. Your users' context would simply call to Send On the queue while, in an asynchronous process SvcBroker would activate a stored procedure which executed in context of higher elevated user. I would opt for this solution rather than relying on a trigger calling an agent job.
I wanted to test the call to Service Broker, so I wrote this simple test example. Instead of calling an SSIS package I simply send an email, but it is very similar to your situation. Notice I use SET TRUSTWORTHY ON at the top of the script. Please read about the implications of this setting.
To run this sample you will need to substitute your email profile info below, <your_email_address_here>, etc.
use Master;
go
if exists(select * from sys.databases where name = 'TestDB')
drop database TestDB;
create database TestDB;
go
alter database TestDB set ENABLE_BROKER;
go
alter database TestDB set TRUSTWORTHY ON;
use TestDB;
go
------------------------------------------------------------------------------------
-- create procedure that will be called by svc broker
------------------------------------------------------------------------------------
create procedure dbo.usp_SSISCaller
as
set nocount on;
declare #dlgid uniqueidentifier;
begin try
-- * figure out how to start SSIS package from here
-- for now, just send an email to illustrate the async callback
;receive top(1)
#dlgid = conversation_handle
from SSISCallerQueue;
if ##rowcount = 0
begin
return;
end
end conversation #dlgid;
exec msdb.dbo.sp_send_dbmail
#profile_name = '<your_profile_here>',
#importance = 'NORMAL',
#sensitivity = 'NORMAL',
#recipients = '<your_email_address_here>',
#copy_recipients = '',
#blind_copy_recipients = '',
#subject = 'test from ssis caller',
#body = 'testing',
#body_format = 'TEXT';
return 0;
end try
begin catch
declare #msg varchar(max);
select #msg = error_message();
raiserror(#msg, 16, 1);
return -1;
end catch;
go
------------------------------------------------------------------------------------
-- setup svcbroker objects
------------------------------------------------------------------------------------
create contract [//SSISCallerContract]
([http://schemas.microsoft.com/SQL/ServiceBroker/DialogTimer] sent by initiator)
create queue SSISCallerQueue
with status = on,
activation (
procedure_name = usp_SSISCaller,
max_queue_readers = 1,
execute as 'dbo' );
create service [//SSISCallerService]
authorization dbo
on queue SSISCallerQueue ([//SSISCallerContract]);
go
return;
-- usage
/*
-- put a row into the queue to trigger the call to usp_SSISCaller
begin transaction;
declare #dlgId uniqueidentifier;
begin dialog conversation #dlgId
from service [//SSISCallerService]
to service '//SSISCallerService',
'CURRENT DATABASE'
on contract [//SSISCallerContract]
with encryption = off;
begin conversation timer (#dlgId)
TIMEOUT = 5; -- seconds
commit transaction;
*/
It would be permissions at the job level. You can possibly assign those users the SQLAgentReaderRole in MSDB to be able to start a job, considering that they would be added to a group that owned the job. If they are not in a group which owns the job, it gets more difficult.

Resources