Service Broker and database ownership mismatch - sql

I have a SQL Server 2008 R2 implementation with Service Broker turned on for a .Net/IIS website running on the same box.
It doesn't throw an error when the global.asax application_startup event fires, however the event log is spammed every second with:
[dbo].[SqlQueryNotificationStoredProcedure-e6946263-93b8-445e-9d92-6fbd49a4b089]'
running on queue
'XXXXXX.dbo.SqlQueryNotificationService-e6946263-93b8-445e-9d92-6fbd49a4b089'
output the following: 'The database owner SID recorded in the master
database differs from the database owner SID recorded in database
'XXXXXXX'. You should correct this situation by resetting the owner of
database 'XXXXXXX' using the ALTER AUTHORIZATION statement.'
Also, the Service Broker is not correctly sending messages (for a SqlCacheDependency) - it basically doesn't work.
I have run the following query and determined there is an ownership mismatch:
SELECT
SUSER_SNAME(d.owner_sid) AS OwnerName
,d.owner_sid AS OwnerSID
,dp.sid AS DboUserSID
,SUSER_SNAME(dp.sid) AS DboUserMapping
FROM sys.databases AS d
JOIN sys.database_principals AS dp ON
dp.name = 'dbo'
WHERE d.database_id = DB_ID();
OwnerName: usrAAAAA
OwnerSID: 0xAAAAA
DboUserMapping: sa
DboUserSID: 0x01
Most places I have seen suggest that I should use ALTER AUTHORIZATION to explicitly set "sa" as the database owner. However, I am unsure if it should be set to sa or usrAAAAA, and I'm not sure if there are any likely implications (what other things could I break? if any).
Any help on this would be greatly appreciated.

Setting the database owner to 'sa' is the most likley to work without causing other problems, but there can be some security related issues with it as explained here: are there reasons I should not set my db owner to sa?.
Note also that, depending on your application requirements and how the accounts are used, if you remove 'usrAAAAA' as the dbo, you may need to add them back in to the DB as a user, and you may also need to give them permissions (such as 'db_owner'). If this is the case, and you have set your database to TRUSTWORTHY (as is often required by Service Broker related usages), then you should probably set the owner to 'usrAAAAA' instead and try to get that to work.

Related

Long term supported method to check 'db_owner' role for a user

I need to check whether a user is db owner.
I've found two methods:
look at "exec sp_helprolemember" output table
select count(*) from (select DbRole = g.name, MemberName = u.name, MemberSID = u.sid from sys.database_principals u, sys.database_principals g, sys.database_role_members m where g.principal_id = m.role_principal_id and u.principal_id = m.member_principal_id and g.name='db_owner') output where MemberName='user_to_be_checked'
Which is, in your opinion, the most long term supported method?
I mean: will it be more likely for Microsoft to commit design changes to system tables structures or stored procedures syntax/output?
And which one is the most portable across SQL Server versions?
Thnx
Raf
Both methods you list are incorrect.
To start with, is always incorrect to check for db_owner membership. The correct check is for CONTROL permission on the database, and the appropriate function to use is HAS_PERM_BY_NAME(). This will save you from the embarrassment of your application refusing to work with an user that has sufficient privileges (CONTROL) because the application uses an incorrect check (role/group membership). This is actually explicitly called out on MSDN:
If the user has the CONTROL DATABASE permission but is not a member of db_owner role, ... will correctly report that the user is not a member of the db_owner role, even though the user has the same permissions.
Finally, if you really need to know role/group membership, the appropriate function is IS_MEMBER()
I would recommend neither actually.
For the catalog view option, Microsoft says:
In future releases of SQL Server, Microsoft may augment the definition
of any system catalog view by adding columns to the end of the column
list. We recommend against using the syntax SELECT * FROM
sys.catalog_view_name in production code because the number of columns
returned might change and break your application.
I believe the same may hold for the system stored procedure.
Instead, I'd suggest using the IS_ROLEMEMBER function. For example:
SELECT IS_ROLEMEMBER('db_owner', 'user1');
It returns 1 if true and 0 if false.
http://technet.microsoft.com/en-us/library/ee677633.aspx
I would think that the system stored procedure - exec sp_helprolemember - would be the long term supported method.
I looked at the source code for exec sp_helprolemember and internally it has the check your are doing in your 2nd method (not verbatim, but it has other conditions also).
Moreover, using Microsoft provided system stored procedures is the recommended way of getting information unless their existing procedures do not give you all the information you want. In that case, you dig deeper and write your own queries against system tables and functions.

Need to learn how to set appropriate permissions on SQL Server database to allow Synchronisation through Sync Framework 2.1

SQL Server is not my strong point and I start to get lost when going past the basic Create Table, Select from Table etc.
I am attempting to set up a database synchronisation scenario with an Microsoft SQLCompact 3.5 database being Synced through a Proxy to and SQL 2008 R2 database. It is being synced through the Microsoft Sync Framework 2.1.
I got everything set up and working fine through the proxy when the user account is the db_owner of the database.
Of course this now needs to be locked down - so I have been trying to restrict the permissions to the bare minimum required for Synchronisation.
According to the Microsoft articles, I need to do the following...
Use the principle of least permission. Do not grant more permissions than are required to perform a specific task. For example, do not grant INSERT permissions for server database tables that are involved in download-only synchronization. Synchronization operations require the following permissions:
EXECUTE permissions on all the stored procedures that Sync Framework uses to read and write to metadata tables and base tables.
SELECT, INSERT, UPDATE, and DELETE permissions for metadata tables and any base tables that will be updated during a synchronization session.
When you provision SQL Server databases that use SqlSyncProvider, be aware of the following permissions requirements for provisioning:
CREATE TABLE permissions to enable creation of the metadata tables: scope_info and scope_config, and the tracking tables that are created for each base table.
ALTER TABLE to add triggers to the base tables.
CREATE PROCEDURE permissions to create the procedures that Sync Framework requires.
SELECT and INSERT permissions for scope_info and scope_config tables.
SELECT permissions for base tables.
I allowed the wizards in Visual Studio 2010 to create the Sync database and proxy for me.
As such - I am unable to find the scope_info and scope_config tables in SQL Server databases, and I am also unable to find the metadata tables so cannot set permissions on these tables. Also - where would I find the stored procedures that the Synchronisation framework is trying to use - I have looked but cannto find them.
Where would I find these and how would I go about setting the appropriate permissions?
I have granted datareader and datawriter, Insert, Update, Delete and Select as well as Execute permissions on the SQL Server database but the sync fails. I have also granted Create Table, Create Procedure and ALTER permissions on the database for the user as well- but still it fails.
If i enable the db_owner role for the user - it works.
The error I receive is:
Unable to initialize the client database, because the schema for table 'tblApplications, tblApplicationConfiguration, tblApplicationInstallProperties, tblApplicationPreRequisites, tblApplicationTypes, tblComputerApps, tblComputers, tblComputerTypes, tblDriveHWSerials, tblDrives, tblDriveTypes, tblFunctions, tblLocationApps, tblLocationComputers, tblLocationIPAddress, tblLocations, tblLocationUsers, tblPermissions, tblRegionLocations, tblRegions, tblRegisteredModules, tblRequestFormats, tblRequestStatus, tblRequestTypes, tblRoles, tblRoleUsers, tblSecurity, tblUsers, tblVehicle, tblVehicleLocationMap, tblVehicleMake, tblRequestProcessingStatus, tblDriveStatus, tblVideoViewTypes' could not be retrieved by the GetSchema() method of DbServerSyncProvider.
Make sure that you can establish a connection to the client database and that either the SelectIncrementalInsertsCommand property or the SelectIncrementalUpdatesCommand property of the SyncAdapter is specified correctly.
I am not able to use the db_owner role when its released.
there are two types of database providers in Sync Framework, the offline provider (SqlCeClientSyncProvider/DbServerSyncProvider) which is used by the Local Database Cache project item and the collaboration/peer-to-peer provider (SqlSyncProvider/SqlCeSyncProvider).
the offline providers dont use the scope_xxx tables as such you wont find it.
assuming you used the default SQL Server Change Tracking when you configured the sync via the wizard, try granting VIEW CHANGE TRACKING permission to the account you're using to connect to the database.
I'm not sure if it will help, but I found this:
Try to set UploadOnly on the SyncTable object instead. When you set it on the SyncAdapterBuidler, the select incremental commands are not generated by the builder. These commands are used to get the table schema from the database. Since these are missing you are getting the schema error.
Also, maybe this blog entry will help.
As JuneT Mentioned, you should turn on Change Tracking
ALTER DATABASE YourDataBaseName
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)

set sql server connection to readonly?

How do I set a SQL server connection to readonly? I tried Googling and all I found was File Mode=Read Only, but it didn't work (File Mode keyword not supported). The reference looked SQL CE specific.
No luck with SQLite Read Only=True either.
-edit-
My connection string is below. I have no clue when it comes to configuring the tables. I don't know how to make users/permissions.
rdconn = new SqlConnection(#"(wrong)Read Only=True;Server=.\SQLExpress;AttachDbFilename=test2.mdf;Database=dbo;Integrated Security=SSPI;User Instance=True;");
Just set on current user's permissions to SELECT only.
Is that what you want?
Click on the current db in SQL Server Management Studio, after click on Security->Users. Find your user, right click on him -> properties->Securable. Just mark SELECT, unmark all others.
Here're links on managing permissions
http://www.databasejournal.com/features/mssql/article.php/2246271/Managing-Users-Permissions-on-SQL-Server.htm
http://www.mssqlcity.com/Articles/Adm/manage_users_permissions.htm
Just found a a free tool for managing permissions. It can be useful too. Check the link
http://www.idera.com/Products/Free-Tools/SQL-permissions/
UPDATE:
If you want the DB to be read-only to any user:
ALTER DATABASE database-name SET READ_ONLY
or read here for more information
http://www.sqlservercurry.com/2009/03/set-database-to-read-only-mode-using.html
http://www.blackwasp.co.uk/SQLReadOnly.aspx
Change the security settings for the used login in SQL server.
For instance only db_datareader.
It's really simple.
If your db-user is called
MyApplicationWebServices_EN
Create a new login called MyApplicationWebServicesReadOnly_EN, with default language English (or whatever you need), who is member of the server-role "public" only (default).
In the DB you want the user to have access to, create a new user called MyApplicationWebServicesReadOnly_EN, and map it to login MyApplicationWebServicesReadOnly_EN.
Right-click the user in the database, and select properties -> general
In the Select-box list for "Membership in database roles", select db_datareader only (make sure all others options are unchecked).
Now use MyApplicationWebServicesReadOnly_EN in your connection string as "user id", and you have your read-only mode..
Of course, if your entire db should be read-only, then
ALTER DATABASE your_database_name SET READ_ONLY
will do just fine, as hgulyan said.
If you want to access the database in readonly mode, you can create a user for database and can enable 'READ' rights and disable 'WRITE' rights
you can see the users under database in sqlserver select that and if you want you can create new user else you can set the rights in properties
Also refer
http://www.zimbio.com/SQL/articles/-jf4iDK7qWQ/Set+database+read+only+mode+using+SQL+Server
In some cases, for instance in a High Availability instance in Azure, you may have a read-only replicated duplicate of your database. In that case, you add
;applicationintent=readonly
to the connection string to have that user reach the Read-Only replica.
More at Microsoft...

Error when creating assembly in SQL: MSG 33009

I'm attempting to load a dll into MSSQL with:
USE dbname
GO
CREATE ASSEMBLY foo
FROM 'C:\foo\foo.dll'
WITH PERMISSION_SET = UNSAFE
GO
And I'm getting an error that states:
Msg 33009, Level 16, State 2, Line 2
The database owner SID recorded in the master database differs from the database owner
SID recorded in database 'dbname'. You should correct this situation by resetting the
owner of database 'dbname' using the ALTER AUTHORIZATION statement.
MSDN really isn't telling me any more about the error than the error tells itself.
I've looked all over the internet and have come to the conclusion that only thing anyone has ever done to avoid this is to:
use dbname
go
EXEC dbo.sp_changedbowner #loginame = N'sa', #map = false
But is changing the owner really the only way to avoid this error? Why do I have to do this, is there another way? I'd like some more information about this error before I go in and blindly change the owner.
I have had exactly the same problem and only solution for me was to change the owner, then change it back again.
The problem is that users are both per-database and per-server. What's happened is that the per-database user has a username that is the same as a per-server user, however they SIDs don't match, so it thinks it could be a different person.
Something you might want to check: If the user that you are logged in as (and are creating the database as) is also mapped to the "model" database, then that user will be created under the users tab for the new database. This means that there are credentials under the Security tab for the instance AND for the local users for the database. To immediately solve the issue, drop the user from the local database - you can then set them back as the owner (from the instance credentials):
drop user [MyUser];
exec sp_changedbowner [MyUser]
To solve this problem long term, unmap the user from the "model" database (Security/Logins/[MyUser] Properties - User Mapping).

Stored Procedure Ownership Chaining

I have several stored procedures in my database that are used to load data from a datamart that is housed in a separate database. These procedures are, generally, in the form:
CREATE PROCEDURE load_stuff
WITH EXECUTE AS OWNER AS
INSERT INTO my_db.dbo.report_table
(
column_a
)
SELECT
column_b
FROM data_mart.dbo.source_table
WHERE
foo = 'bar';
These run fine when I execute the query in SQL Server Management Studio. When I try to execute them using EXEC load_stuff, the procedure fails with a security warning:
The server principal "the_user" is not able to access the database "data_mart" under the current security context.
The OWNER of the sproc is dbo, which is the_user (for the sake of our example). The OWNER of both databases is also the_user and the_user is mapped to dbo (which is what SQL Server should do).
Why would I be seeing this error in SQL Server? Is this because the user in question is being aliased as dbo and I should use a different user account for my cross-database data access?
Edit
I understand that this is because SQL Server disables cross database ownership chaining by default, which is good. However, I'm not sure of the best practice in this situation. If anyone has any input on the best practice for this scenario, it would be greatly appreciated.
Edit 2
The eventual solution was to set TRUSTWORTHY ON on both of the databases. This allows for limited ownership chaining between the two databases without resorting to full database ownership chaining.
Why not remove EXECUTE AS OWNER?
Usually, my user executing the SP would have appropriate rights in both databases, and I don't have to do that at all.
There is no need to create login, you can just enable guest user in target DB.
grant connect to guest
This allows executing user to enter DB under guest context, and when "db chaining is ON access will not be checked in target DB.
Actually, DBO is a role (you can consider it as a group of users), not a user in himself. (Unless you can connect to SQL SERVER using dbo:passwordfordbo it's not a user).
Usually, in the wonderful world of SQL Server, if you grant userX right to execute storedprocY then X gets the right to perform all the task Y contains even if he doesn't have all the permission on all the objects used in Y.
That's an extremely useful feature to encapsulate business logic in a stored procedure. (Your user have NO access on the table but they do can EXECUTE one stored proc).
When we talk about "ownership chaining" it means the following (please correct me if I am wrong though)
- If ownership chaining is disabled: the right to execute procedureX will work as long as all the required objects are in the same database
- Of chaining is enabled: That "privilege" will expands towards all databases.
Hope that helps,