Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
jteeter
Starting Member
4 Posts |
Posted - 2008-03-14 : 06:39:33
|
In writing an event processor for handling database management events, I can't seem to see the database that's just been restored, attached, or created.All I'd like to do is automate the granting of permissions on the new database - I can't use model permissions because I need to handle restores and attaches as well.First I got this working inside a CREATE_DATABASE DDL trigger, but shockingly that didn't get fired when I ran a create for attach, and unsurprising it didn't get fired on a restore.So now I'm trying to do it in an activation stored procedure on the AUDIT_DATABASE_MANAGEMENT_EVENT, which does get invoked on all types of creates - a basic create, a create for attach, and a restore.But inside the activation stored procedure, the only databases I seem to have access to are master, tempdb, and the database with the activation procedure itself. All other databases seem to be absent in the security context, even though I'm executing AS SELF under a local admin account.I can probably execute an xp_cmdshell and run sqlcmd to grant the permissions, but that seems like a hack.Any suggestions? Is there another event driven way to do this?Running SQL Server version:Microsoft SQL Server 2005 - 9.00.3054.00 (Intel X86) Mar 23 2007 16:28:52 Copyright (c) 1988-2005 Microsoft Corporation Developer Edition on Windows NT 5.1 (Build 2600: Service Pack 2)Sample script follows:USE master;GOIF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'MyAuditTestDB')BEGIN CREATE DATABASE MyAuditTestDB;END;GO IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'MyAuditTestDB' AND is_broker_enabled = 1)BEGIN ALTER DATABASE MyAuditTestDB SET ENABLE_BROKER;END;GOUSE MyAuditTestDB;GOIF OBJECT_ID('dbo.tblDBAudit') IS NOT NULLBEGIN DROP TABLE dbo.tblDBAudit;ENDGOCREATE TABLE dbo.tblDBAudit (auditEntry xml NOT NULL);GOIF OBJECT_ID('dbo.tblDBsVisible') IS NOT NULLBEGIN DROP TABLE dbo.tblDBsVisible;ENDGOCREATE TABLE dbo.tblDBsVisible (activation_time datetime, name sysname, create_date datetime);GOIF OBJECT_ID('dbo._sp_DBQActivation') IS NOT NULLBEGIN DROP PROCEDURE dbo._sp_DBQActivation;ENDGOCREATE PROCEDURE dbo._sp_DBQActivationASBEGIN DECLARE @msg_body xml; BEGIN TRANSACTION BEGIN TRY PRINT 'Processing database management audit event...'; RECEIVE TOP(1) @msg_body = CASE WHEN validation = 'X' THEN CAST(message_body AS XML) ELSE NULL END FROM dbo.DBQ; IF @msg_body IS NOT NULL BEGIN/* What I want to do is figure out what database was created, then add permissions: exec [newdb].dbo.sp_addrolemember 'db_backupoperator', 'User1' exec [newdb].dbo.sp_addrolemember 'db_datareader', 'User1' exec [newdb].dbo.sp_addrolemember 'db_owner', 'User2'but I can't see any databases but master, tempdb, and MyAuditTestDB*/ INSERT INTO dbo.tblDBsVisible SELECT GETDATE(), name, create_date FROM sys.databases; INSERT INTO dbo.tblDBAudit SELECT @msg_body; END; END TRY BEGIN CATCH PRINT ERROR_MESSAGE(); END CATCH COMMIT TRANSACTIONENDGOIF EXISTS(SELECT * FROM sys.services WHERE name = 'DBSvc') DROP SERVICE DBSvc ;GOIF OBJECT_ID('DBQ') IS NOT NULL AND EXISTS(SELECT * FROM sys.service_queues WHERE name = 'DBQ') DROP QUEUE dbo.DBQ;GOCREATE QUEUE dbo.DBQ -- Activation turned on WITH STATUS = ON, ACTIVATION ( PROCEDURE_NAME = MyAuditTestDB.dbo._sp_DBQActivation, MAX_QUEUE_READERS = 1, EXECUTE AS SELF ) ON [DEFAULT] ;GOCREATE SERVICE DBSvc ON QUEUE dbo.DBQ ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]);IF EXISTS(SELECT * FROM sys.server_event_notifications WHERE name = 'EventNotifyDB') DROP EVENT NOTIFICATION EventNotifyDB ON SERVER ;GOCREATE EVENT NOTIFICATION EventNotifyDBON SERVERFOR AUDIT_DATABASE_MANAGEMENT_EVENTTO SERVICE 'DBSvc', 'current database';GO/* Now that we're setup, execute a bunch of items that should fire the event */CREATE DATABASE TestingAuditDBEventON( Name = 'TestingAuditDBEventDB', FILENAME = N'C:\TestingAuditDBEvent.mdf' )LOG ON( Name = 'TestingAuditDBEventLog', FILENAME = N'C:\TestingAuditDBEvent.LDF' )GOBACKUP DATABASE TestingAuditDBEvent TO DISK = N'C:\TestingAuditDBEvent.bak' WITH NOFORMAT, INIT, NAME = N'TestingAuditDBEventBackup', SKIP, NOREWIND, NOUNLOAD, STATS = 10GODROP DATABASE TestingAuditDBEventGORESTORE DATABASE TestingAuditDBEvent FROM DISK = N'C:\TestingAuditDBEvent.bak' WITH FILE = 1, MOVE N'TestingAuditDBEventLog' TO N'C:\TestingAuditDBEvent.LDF', NOUNLOAD, STATS = 10GOEXECUTE sp_detach_db 'TestingAuditDBEvent'GOCREATE DATABASE TestingAuditDBEventON( FILENAME = N'C:\TestingAuditDBEvent.mdf' ),( FILENAME = N'C:\TestingAuditDBEvent.LDF' )FOR ATTACHGODROP DATABASE TestingAuditDBEventGO/* Let's find out what we saw inside the event context */SELECT * FROM dbo.tblDBsVisible;SELECT * FROM dbo.tblDBAudit;GO/* Cleanup our test environment */IF EXISTS(SELECT * FROM sys.server_event_notifications WHERE name = 'EventNotifyDB') DROP EVENT NOTIFICATION EventNotifyDB ON SERVER ;IF EXISTS(SELECT * FROM sys.services WHERE name = 'DBSvc') DROP SERVICE DBSvc ;IF OBJECT_ID('DBQ') IS NOT NULL AND EXISTS(SELECT * FROM sys.service_queues WHERE name = 'DBQ') DROP QUEUE dbo.DBQ;IF OBJECT_ID('dbo.tblDBAudit') IS NOT NULLBEGIN DROP TABLE dbo.tblDBAudit;ENDIF OBJECT_ID('dbo.tblDBsVisible') IS NOT NULLBEGIN DROP TABLE dbo.tblDBsVisible;ENDIF OBJECT_ID('dbo._sp_DBQActivation') IS NOT NULLBEGIN DROP PROCEDURE dbo._sp_DBQActivation;ENDUSE MASTERGOIF EXISTS (SELECT * FROM sys.databases WHERE name = 'MyAuditTestDB')BEGIN DROP DATABASE MyAuditTestDB;END |
|
rmiao
Master Smack Fu Yak Hacker
7266 Posts |
Posted - 2008-03-14 : 22:53:59
|
Ensure your account has db creation permission. |
|
|
jteeter
Starting Member
4 Posts |
Posted - 2008-03-15 : 02:26:55
|
Rmiao, thanks for the advice. My account does have db create privileges - it's a local admin on the machine... The dbs get created, I just can't see them from the activation procedure.Were you able to see other databases running the above script? Did it return anything other than the tempdb, master, and the test db? In mine I can't even see model or msdb from the query, let alone the databases that cause the events to be fired. |
|
|
rmiao
Master Smack Fu Yak Hacker
7266 Posts |
Posted - 2008-03-15 : 16:03:07
|
Tried connect to sql with sa then run the script? |
|
|
jteeter
Starting Member
4 Posts |
Posted - 2008-03-17 : 06:48:22
|
I was/am connected as a local admin, which acts as a sa on the database instance. The script runs without errors, but just doesn't get access to any other databases. |
|
|
jteeter
Starting Member
4 Posts |
Posted - 2008-03-17 : 07:07:05
|
Many thanks to Remus Rusanu and his wonderful service broker blog. Apparently even with execute as self, SQL Server doesn't really trust the stored procedure we're running. The problem is described fully in http://blogs.msdn.com/remusrusanu/archive/2006/01/12/512085.aspx.Two solutions. If it's an internal system (not production), or if your dbos are already sysadmins on the database, you can just mark the database as trustworthy - ALTER DATABASE MyAuditTestDB SET TRUSTWORTHY ON;That solves my needs because I'm only doing this automatic granting on development servers. If you need a production solution, you can "sign the activation stored procedure" as trusted. Sample code is at http://rusanu.com/2006/03/01/signing-an-activated-procedure/Finally, for a description of why you can't use TRUSTWORHTY ON unless you really, really trust the dbo of the database see http://msdn2.microsoft.com/en-us/library/ms188304.aspx. |
|
|
|
|
|
|
|