web-dev-qa-db-fra.com

Créer une connexion avec SID comme chaîne

J'essaie de créer un identifiant comme suit:

CREATE LOGIN [Test] WITH PASSWORD='Test123', SID=SID_BINARY(N'S-1-5-21-408552231-458724953-3089381293-513')

Mais peu importe à quoi il ressemble, SID n'accepte qu'une entrée binaire, aucune sous-requête ou autre chose vraiment.

Incorrect syntax near 'SID'.

Existe-t-il un moyen de créer une connexion avec SID avec une chaîne?

4
Roger Far

Une chose amusante à propos de SID_BINARY() - il génère binary(28) dans ce cas, alors que CREATE LOGIN Attend binary(16). Comme le souligne Solomon, et en ajoutant ici afin qu'il n'y ait aucune ambiguïté, cela signifie qu'il n'y a aucun moyen de créer un SID SQL Server basé sur - ou qui peut correspondre à - l'identifiant Windows que vous avez publié dans votre question. Vous voulez CREATE LOGIN ... FROM Windows pour cela.

Cependant, votre premier problème est l'erreur de syntaxe. La raison pour laquelle vous obtenez cela est parce que vous ne pouvez pas utiliser d'expressions dans une instruction CREATE LOGIN, Et qu'elle ne prend pas non plus de variables, vous devez donc construire du SQL dynamique.

J'ai essayé d'utiliser les 28 octets comme suit:

DECLARE @sid_in varchar(100);
SET @sid_in = 'S-1-5-21-408552231-458724953-3089381293-513';

DECLARE @sql nvarchar(max) = N'CREATE LOGIN [Test] WITH PASSWORD = N''foo'',
  SID = ' + CONVERT(varchar(64), SID_BINARY(@sid_in), 1) + N';';

PRINT @sql;

A abouti:

CREATE LOGIN [Test] WITH PASSWORD = N'foo', 
  SID = 0x01050000000000051500000027035A185996571BAD3724B801020000;

Bien sûr, l'exécution de SQL a généré une erreur, comme je m'y attendais:

Msg 15419, niveau 16, état 1
Le paramètre sid fourni doit être binaire (16).

Alors je me suis demandé si la troncature à 16 octets fonctionnerait. Je pensais que c'était incompatible car perdre 12 octets devrait être un problème:

DECLARE @sid_in varchar(100), @sid_out varchar(100);
SET @sid_in = 'S-1-5-21-408552231-458724953-3089381293-513';

SELECT original = SID_BINARY(@sid_in);
SELECT trimmed  = CONVERT(binary(16), SID_BINARY(@sid_in));

Résultats:

original
----------------------------------------------------------
0x01050000000000051500000027035A185996571BAD3724B801020000

trimmed
0x01050000000000051500000027035A18

Mais ensuite je l'ai essayé, et ça a (en quelque sorte) fonctionné. Voici un exemple:

DECLARE @sid_in varchar(100);
SET @sid_in = 'S-1-5-21-408552231-458724953-3089381293-513';

DECLARE @sql nvarchar(max) = N'CREATE LOGIN [Test] WITH PASSWORD = N''foo'',
  SID = ' + CONVERT(varchar(64), CONVERT(binary(16),SID_BINARY(@sid_in)), 1) + N';';

EXEC sys.sp_executesql @sql;

Et pour prouver que couper ces 12 octets a peu d'effet:

DECLARE @sid_in varchar(100);
SET @sid_in = 'S-1-5-21-408552231-458724953-3089381293-513';

SELECT SUSER_SNAME(CONVERT(binary(16),SID_BINARY(@sid_in)));

Résultats:

----
Test

Cela signifie simplement que vous pouvez écrire votre code de telle manière que vous puissiez toujours accéder à la bonne connexion en raison de l'identifiant Windows S-1 .... Mais il y a un effet secondaire de cette coupe qui peut ou non être important pour vous. Il est impossible de revenir au SID d'origine que vous avez transmis car certaines de ces données ont disparu. Donc, si vous créez les fonctions @eckes le soulignent ci-dessus , vous trouverez une sortie légèrement différente de ce que vous attendez:

SELECT name, sid, ws1 = dbo.fn_SIDToString(sid) 
  FROM sys.server_principals 
  WHERE name = N'Test';

Résultats:

name    sid                                   ws1
----    ----------------------------------    ------------------
Test    0x01050000000000051500000027035A18    S-1-5-21-408552231

Cela peut être acceptable ou non. Je ne connais pas suffisamment les identifiants Windows ni pourquoi vous souhaitez créer un utilisateur d'authentification SQL qui est  apparaît à première vue comme étant mappé à un pour savoir si cela répondra à vos besoins. Mais il surmonte à la fois l'erreur de syntaxe et le problème 28/16.


Fonction que j'ai utilisée, incluse ici au cas où le lien mourrait:

CREATE FUNCTION [dbo].[fn_SIDToString]
(
  @BinSID AS VARBINARY(100)
)
RETURNS VARCHAR(100)
AS BEGIN

  IF LEN(@BinSID) % 4 <> 0 RETURN(NULL)

  DECLARE @StringSID VARCHAR(100)
  DECLARE @i AS INT
  DECLARE @j AS INT

  SELECT @StringSID = 'S-'
     + CONVERT(VARCHAR, CONVERT(INT, CONVERT(VARBINARY, SUBSTRING(@BinSID, 1, 1)))) 
  SELECT @StringSID = @StringSID + '-'
     + CONVERT(VARCHAR, CONVERT(INT, CONVERT(VARBINARY, SUBSTRING(@BinSID, 3, 6))))

  SET @j = 9
  SET @i = LEN(@BinSID)

  WHILE @j < @i
  BEGIN
    DECLARE @val BINARY(4)
    SELECT @val = SUBSTRING(@BinSID, @j, 4)
    SELECT @StringSID = @StringSID + '-'
      + CONVERT(VARCHAR, CONVERT(BIGINT, CONVERT(VARBINARY, REVERSE(CONVERT(VARBINARY, @val))))) 
    SET @j = @j + 4
  END
  RETURN ( @StringSID ) 
END
3
Aaron Bertrand

La documentation indique que CREATE LOGIN accepte la valeur SID comme type de données binaire (accentuation mine):

SID = sid

Utilisé pour recréer une connexion. S'applique uniquement aux connexions d'authentification SQL Server, pas aux connexions d'authentification Windows. Spécifie le SID de la nouvelle connexion d'authentification SQL Server. Si cette option n'est pas utilisée, SQL Server attribue automatiquement un SID. La structure SID dépend de la version de SQL Server. SID de connexion SQL Server: valeur littérale de 16 octets (binaire (16)) basée sur un GUID. Par exemple, SID = 0x14585E90117152449347750164BA00A7.

et

DROP LOGIN TestLogin;  
GO  

CREATE LOGIN TestLogin   
WITH PASSWORD = 'SuperSecret52&&', SID = 0x241C11948AEEB749B0D22646DB1A19F2;  

SELECT * FROM sys.sql_logins WHERE name = 'TestLogin';  
GO

Vous pouvez utiliser sp_help_revlogin comme exemple de méthode courante pour extraire la valeur SID binaire pour générer CREATE LOGIN instructions pour les connexions existantes - si vous travaillez avec une connexion SQL. Il semble que travailler avec des comptes Windows sur une connexion SQL soit beaucoup plus délicat.

1
LowlyDBA

La réponse est simple: vous ne pouvez pas faire ça!

Vous essayez de créer une connexion SQL Server (c'est-à-dire WITH PASSWORD='Test123', SID=... au lieu de FROM ...) mais en utilisant un SID Windows (c'est-à-dire 0x01050000000000051500000027035A185996571BAD3724B801020000 au lieu de quelque chose du genre 0x4D50DEDF91DABA4595F121BBA9E8D4AF). La documentation, citée dans réponse de LowlyDBA indique:

S'applique uniquement aux connexions d'authentification SQL Server, pas aux connexions d'authentification Windows.

Et vous n'avez pas obtenu le SID que vous essayez d'utiliser à partir d'une connexion SQL Server. Il n'y a aucun moyen de faire fonctionner cela. La seule raison pour laquelle l'approche d'Aaron apparaît pour fonctionner (je fais référence seulement au SID qu'il utilise; le truc SQL dynamique est tout à fait correct) en coupant les octets excédentaires pour qu'il ne reste que 16 octets. Mais cela fait la valeur résultante, 0x01050000000000051500000027035A18, tout aussi arbitraire que de trouver quelque chose par vous-même comme 0x0102030405060708090A0B0C0D0E0F10. Les SID de connexion SQL Server ne sont que cela: des identifiants arbitraires. Par exemple:

CREATE LOGIN [Whozitz] WITH PASSWORD='Test123', SID=0x0102030405060708090A0B0C0D0E0F10;

SELECT SUSER_SNAME(0x0102030405060708090A0B0C0D0E0F10);
-- Whozitz

Pourtant, vous commenciez par S-1-5-21-408552231-458724953-3089381293-513, qui est un identifiant significatif: non seulement il fait référence à une entité spécifique connue du système d'exploitation (ou à un système d'exploitation quelque part car il pourrait provenir d'un système différent), mais aussi aux parties séparées par des tirets dans la chaîne/La forme SDDL du SID a une signification. Le "1" est le numéro de version et ne change jamais. Le "5" fait référence au type d'entité, je crois. Et le reste des segments sont basés sur le type.

Mais, même si un SID correspondait entièrement entre SQL Server et le système d'exploitation, le fait que le serveur principal/connexion est une connexion SQL Server signifie qu'il n'y a pas de connexion réelle entre le SID dans SQL Serveur et SID au niveau du système d'exploitation.

Si vous souhaitez créer des connexions SQL Server basées sur les SID des connexions qui existent sur d'autres systèmes afin que vous puissiez déplacer des bases de données et ne pas avoir à synchroniser les connexions après coup, ou quelque chose comme ça, alors vous ne pouvez le faire qu'avec les connexions existantes SQL Server , pas les connexions Windows.

1
Solomon Rutzky