web-dev-qa-db-ja.com

文字列としてSIDを使用してログインを作成する

次のようにログインを作成しようとしています。

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

しかし、SIDがどのように見えるかに関係なく、バイナリ入力のみを受け入れ、サブクエリなどは実際には受け入れません。

Incorrect syntax near 'SID'.

文字列を使用してSIDでログインを作成する方法はありますか?

4
Roger Far

SID_BINARY()の面白いところ-この場合はbinary(28)を出力しますが、_CREATE LOGIN_はbinary(16)を期待します。ソロモンが指摘し、曖昧さがないようにここに追加すると、これは投稿したWindows識別子に基づいて、またはそれにマップできるSQL Server SIDを作成する方法がないことを意味しますあなたの質問です。_CREATE LOGIN ... FROM Windows_が必要です。

ただし、最初の問題は構文エラーです。これが発生する理由は、_CREATE LOGIN_ステートメントで式を使用できず、変数も使用できないため、動的SQLを構築する必要があるためです。

次のように28バイトすべてを使用しようとしました。

_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;
_

収量:

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

もちろん、予想どおり、そのSQLを実行するとエラーが発生しました。

メッセージ15419、レベル16、状態1
指定されたパラメーターsidは、binary(16)である必要があります。

だから私は16バイトに切り捨てることがうまくいくかどうか疑問に思いました。 12バイトの損失が問題になるはずなので、これは互換性がないと思いました:

_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));
_

結果:

_original
----------------------------------------------------------
0x01050000000000051500000027035A185996571BAD3724B801020000

trimmed
0x01050000000000051500000027035A18
_

しかし、私はそれを試しました、そしてそれは(一種の)うまくいきました。次に例を示します。

_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;
_

そして、これらの12バイトをトリミングしてもほとんど効果がないことを証明するには、次のようにします。

_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)));
_

結果:

_----
Test
_

これは、Windows S-1 ...識別子が与えられた場合でも正しいログインに到達できるようにコードを記述できることを意味します。ただし、このトリミングには副作用がある場合とない場合があります。一部のデータがなくなっているため、渡した元のSIDに戻すことはできません。したがって、作成した場合 関数@eckesは上記を指します の場合、予想とは少し異なる出力が見つかります。

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

結果:

_name    sid                                   ws1
----    ----------------------------------    ------------------
Test    0x01050000000000051500000027035A18    S-1-5-21-408552231
_

それは許容される場合と許容されない場合があります。 Windows識別子について、またはSQL認証ユーザーを作成する理由を正確には知りません。 です 一見すると、これがあなたのニーズを満たすかどうかを知るために1つにマッピングされるように見えます。しかし、それは構文エラーと28/16問題の両方を通過します。


私が使用した機能、リンクが切れた場合に備えてここに含まれています:

_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

ドキュメントには CREATE LOGIN がSID値をバイナリデータ型として受け入れると記載されています(私の強調):

SID = sid

ログインを再作成するために使用されます。 SQL Server認証ログインのみに適用され、Windows認証ログインには適用されません。新しいSQL Server認証ログインのSIDを指定します。このオプションを使用しない場合、SQL Serverは自動的にSIDを割り当てます。 SID構造は、SQL Serverのバージョンによって異なります。 SQL ServerログインSID:GUIDに基づく16バイト(binary(16))リテラル値たとえば、SID = 0x14585E90117152449347750164BA00A7。

そして

DROP LOGIN TestLogin;  
GO  

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

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

SQLログインを使用している場合、バイナリSID値を抽出して既存のログインのCREATE LOGINステートメントを生成する一般的な方法の例として、 sp_help_revlogin を使用できます。 SQLログインでWindowsアカウントを操作するのはかなり難しいようです。

1
LowlyDBA

答えは簡単です。これを行うことはできません。

SQL Serverログイン(つまり、WITH PASSWORD='Test123', SID=...ではなくFROM ...)を作成しようとしていますが、Windows SID(つまり、0x01050000000000051500000027035A185996571BAD3724B801020000の線に沿ったものではなく0x4D50DEDF91DABA4595F121BBA9E8D4AF)を使用しています。 LowlyDBAの回答 で引用されているドキュメントには、次のように記載されています。

SQL Server認証ログインのみに適用され、Windows認証ログインには適用されません。

また、SQL Serverログインから使用しようとしているSIDを取得していません。これを機能させる方法はありません。アーロンのアプローチが動作するように見える唯一の理由(私は彼が使用しているSIDにonlyを参照しています;動的SQLのもの完全に正しいです)は、残りのバイトが16バイトだけになるように、余分なバイトを切り落とすことです。しかし、これを行うと、結果の値0x01050000000000051500000027035A18が、0x0102030405060708090A0B0C0D0E0F10のような独自の値を思いつくのと同じくらい恣意的になります。 SQL ServerログインSIDは、任意の識別子です。例えば:

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

SELECT SUSER_SNAME(0x0102030405060708090A0B0C0D0E0F10);
-- Whozitz

それでも、意味のある識別子であるS-1-5-21-408552231-458724953-3089381293-513から始めました。OS(または別のシステムから取得された可能性があるため、OSのどこかにある特定のエンティティ)を参照するだけでなく、文字列内のダッシュで区切られた/ SIDのSDDL形式は意味があります。 「1」はバージョン番号であり、決して変更されません。 「5」はエンティティのタイプを指していると思います。そして、残りのセグメントはタイプに基づいています。

ただし、SIDがSQL ServerとOSの間で完全に一致した場合でも、サーバープリンシパル/ログインがSQL Serverログインであるという事実は、実際の接続がないことを意味しますSQL Server内のSIDおよびOSレベルのSID。

他のシステムに存在するログインのSIDに基づいてSQL Serverログインを作成して、データベースを移動し、事後にログインを同期する必要がないようにする場合などは、以下の方法でのみ実行できます。 Windowsログインではなく、既存SQL Serverログイン。

1
Solomon Rutzky