7 – Securing access to SQL Server 195 on - Used byb sp_trace_setevent to turn on data columns for particular events */ DECLARE @traceError INT, @TraceID INT, @on BIT SET @on = 1 Create the trace and store the output in traceError, then test traceError for failure and alert the user if the trace cannot be started EXEC @traceError = sp_trace_create @TraceID output, 0, @traceFile, @maxFileSize, NULL IF @traceError <> 0 BEGIN PRINT('Trace could not be started: ' + @traceError) RETURN END Add events that we want to collect data on for the trace Audit Login events (14) exec sp_trace_setevent @TraceID, 14, 1, @on exec sp_trace_setevent @TraceID, 14, 9, @on exec sp_trace_setevent @TraceID, 14, 6, @on exec sp_trace_setevent @TraceID, 14, 10, @on exec sp_trace_setevent @TraceID, 14, 14, @on exec sp_trace_setevent @TraceID, 14, 11, @on exec sp_trace_setevent @TraceID, 14, 12, @on Audit Logout events (15) exec sp_trace_setevent @TraceID, 15, 15, @on exec sp_trace_setevent @TraceID, 15, 16, @on exec sp_trace_setevent @TraceID, 15, 9, @on exec sp_trace_setevent @TraceID, 15, 13, @on exec sp_trace_setevent @TraceID, 15, 17, @on exec sp_trace_setevent @TraceID, 15, 6, @on exec sp_trace_setevent @TraceID, 15, 10, @on exec sp_trace_setevent @TraceID, 15, 14, @on exec sp_trace_setevent @TraceID, 15, 18, @on exec sp_trace_setevent @TraceID, 15, 11, @on exec sp_trace_setevent @TraceID, 15, 12, @on ExistingConnection events (17) exec sp_trace_setevent @TraceID, 17, 12, @on exec sp_trace_setevent @TraceID, 17, 1, @on exec sp_trace_setevent @TraceID, 17, 9, @on exec sp_trace_setevent @TraceID, 17, 6, @on exec sp_trace_setevent @TraceID, 17, 10, @on exec sp_trace_setevent @TraceID, 17, 14, @on exec sp_trace_setevent @TraceID, 17, 11, @on RPC:Completed events (10) exec sp_trace_setevent @TraceID, 10, 15, @on exec sp_trace_setevent @TraceID, 10, 16, @on 7 – Securing access to SQL Server 196 exec sp_trace_setevent @TraceID, 10, 1, @on exec sp_trace_setevent @TraceID, 10, 9, @on exec sp_trace_setevent @TraceID, 10, 17, @on exec sp_trace_setevent @TraceID, 10, 10, @on exec sp_trace_setevent @TraceID, 10, 18, @on exec sp_trace_setevent @TraceID, 10, 11, @on exec sp_trace_setevent @TraceID, 10, 12, @on exec sp_trace_setevent @TraceID, 10, 13, @on exec sp_trace_setevent @TraceID, 10, 6, @on exec sp_trace_setevent @TraceID, 10, 14, @on SQL:BatchCompleted events (12) exec sp_trace_setevent @TraceID, 12, 15, @on exec sp_trace_setevent @TraceID, 12, 16, @on exec sp_trace_setevent @TraceID, 12, 1, @on exec sp_trace_setevent @TraceID, 12, 9, @on exec sp_trace_setevent @TraceID, 12, 17, @on exec sp_trace_setevent @TraceID, 12, 6, @on exec sp_trace_setevent @TraceID, 12, 10, @on exec sp_trace_setevent @TraceID, 12, 14, @on exec sp_trace_setevent @TraceID, 12, 18, @on exec sp_trace_setevent @TraceID, 12, 11, @on exec sp_trace_setevent @TraceID, 12, 12, @on exec sp_trace_setevent @TraceID, 12, 13, @on SQL:BatchStarting events (13) exec sp_trace_setevent @TraceID, 13, 12, @on exec sp_trace_setevent @TraceID, 13, 1, @on exec sp_trace_setevent @TraceID, 13, 9, @on exec sp_trace_setevent @TraceID, 13, 6, @on exec sp_trace_setevent @TraceID, 13, 10, @on exec sp_trace_setevent @TraceID, 13, 14, @on If a filter has been used, setup the filter column and the keyword using sp_trace_setfilter IF @filterColumn > 0 BEGIN EXEC sp_trace_setfilter @traceID, @filterColumn, 0, 6, @filterKeyword END Set the trace to status 1, running EXEC sp_trace_setstatus @TraceID, 1 Log all needed trace information in the Trace_IDs table using the linked repository server Change linked server name here INSERT INTO MYSERVER123.DBA_Info.dbo.Trace_IDs ( TraceName, TraceID, TraceFile, TraceServer ) VALUES ( @traceName, @TraceID, @traceFile, CONVERT(nvarchar(128), SERVERPROPERTY('ServerName')) ) 7 – Securing access to SQL Server 197 Notify user of trace creation PRINT('Trace Started') SET NOCOUNT OFF GO Listing 7.11: usp_startTrace. Remember that the structure of the trace_data table in version-dependent, and the one shown in Listing 7.11 is specific to SQL Server 2005 (the SQL 2000 equivalent is in the download). The central storage database can house both 2000 and 2005 data, but will use different tables depending on the version. The stored procedures are also version dependant and are respectively named. The reason for the slight difference is that the two versions handle trace data differently and have slightly differing schema. The second script, usp_stopTrace, is shown in Listing 7.12 and uses the data stored about the trace to archive the data and to close the trace after completion. USE [msdb] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO /* Procedure Name : usp_stopTrace Parameter 1 : traceName - Unique identifier of trace to be stopped [Req] */ CREATE PROCEDURE [dbo].[usp_stopTrace] @traceName NVARCHAR(50) AS SET NOCOUNT ON /* Variable Declaration traceID - Will hold the ID of the trace that will be stopped and archived traceFile - The physical file to export data from command - Variable to hold the command to clean the traceFile from the server */ DECLARE @traceID INT, @traceFile NVARCHAR(100), 7 – Securing access to SQL Server 198 @command NVARCHAR(150) Test for the trace via name in the repository, if it exsists proccess it, if not alert the user Change linked server name here IF EXISTS ( SELECT * FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName') ) BEGIN Gather the traceID and traceFile from the respository Change linked server name here SET @traceID = (SELECT TraceID FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName')) Change linked server name here SET @traceFile = (SELECT TraceFile FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName')) Set the status of the trace to inactive, then remove the trace from the server EXEC sp_trace_setstatus @traceID, 0 EXEC sp_trace_setstatus @traceID, 2 Archive the older trace data and remove all records to make room for the new trace data Change linked server name here INSERT INTO MYSERVER123.DBA_Info.dbo.trace_archive SELECT * FROM MYSERVER123.DBA_Info.dbo.trace_table Change linked server name here DELETE FROM MYSERVER123.DBA_Info.dbo.trace_table Change linked server name here INSERT INTO MYSERVER123.DBA_Info.dbo.trace_table SELECT * FROM ::fn_trace_gettable(@traceFile + '.trc', default) Remove the existing trace file for future use SET @command = 'DEL ' + @traceFile + '.trc' EXEC xp_cmdshell @command Delete the trace information from the repository Change linked server name here DELETE FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName') Alert the user that the trace has been stopped and archived PRINT('Trace ' + @traceName + ' Stopped and Archived') 7 – Securing access to SQL Server 199 RETURN END Alert the user that the trace was not found in the repository PRINT('Trace ' + @traceName + ' Not Found') SET NOCOUNT OFF GO Listing 7.12: usp_stopTrace. The procedure takes only one parameter, traceName, which it uses to query the central server to retrieve all of the data that was stored by the usp_startTrace script. This information includes the name, trace id and trace file. Once the data has been received, the trace is stopped and the records from the trace_data table are archived into the trace_archive table. The new trace file is then pushed into the trace_data table. So, you can always find the newest trace data in the trace_data table and any older trace information in the trace_archive table. The trace file is then deleted from the server, via xp_cmdshell, and the trace identity is removed from the central repository to free up the trace name and id for future use. Implementation There are just a few steps that you will need to take in order to get these trace procedures working correctly in your environment. • Choose a main repository for your trace data, and modify the procedures to point to the machine on which you want to store the trace data. For example, I have my database, DBA_Info, residing on a test machine. Any version of SQL Server will work for the storage of data; the differences in the scripts are only due to changes in definitions of data collected in the traces. • Create a new database for the trace data, using the create database/table scripts included in the source code zip file, to hold all of this data. You only need to run the create scripts for the version of the script you will be using, or both if you will be using the procedures on multiple machines, utilizing both SQL 2000 and SQL 2005. The results from either version are stored in separate tables so your repository database can contain both 2000 and 2005 archive trace data. . user Change linked server name here IF EXISTS ( SELECT * FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName') . Change linked server name here SET @traceID = (SELECT TraceID FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName')). Change linked server name here SET @traceFile = (SELECT TraceFile FROM MYSERVER123.DBA_Info.dbo.Trace_IDs WHERE TraceName = @traceName AND TraceServer = SERVERPROPERTY('ServerName'))