SID と名前の変換 ~ SID ルックアップ・ツール

Windows の仕組みは "誰が" 何をしたいのか、ということが基本となるセキュリティシステムです。 その意味でユーザーを識別するということはとても大切です。

ここでは詳細は省きますが、 ユーザーアカウントには、ユーザー名やパスワード (いわゆるクレデンシャル) 情報やコメント、住所の他に、 ユーザーを識別するための ID である SID (Security SID) が含まれています。

SID の実体は可変長のバイナリデータですが、読解可能なテキスト表現も可能です。 S-R-I-S-S フォーマットというものです。この詳細は今回は省略しますが、 要はユーザー名と SID (のテキスト表現) の相互変換が可能なのです。

今回 SID ルックアップツール という簡単なツールを作りました。 これを使うと、SID とユーザー名の変換が出来ます。

このツールはこちらからダウンロード可能です。

sidlookup.zip

このツールは、いろんなユーザー名を入力して SID にしてみて遊ぶ (?) だけではなく、様々なトラブルシューティングにも利用できます。

通常セキュリティで保護するオブジェクト、データ等を作成する場合は、「どのユーザー」 に 「どの権限を与える・拒否する」 という形で設定します。こういう場合ユーザーを登録すると、そのデータ内に SID を残します。その後、ユーザーアカウントを削除するなどすると、 プライベートなデータ内にのみ SID が残る場合があります。

このような SID が有効なデータなのかどうか確認する時に、このツールを使うと良いでしょう。ユーザーを再作成したのにうまく動かない、というようなトラブル解決・原因調査に役立ちます。

SID ルックアップツールの作成

次のコードを sidlookup.cpp として保存します。

#include "resource.h"

#include <windows.h>
#include <windowsx.h>
#include <Sddl.h>

#include <tchar.h>
#include <stdio.h>
#include <assert.h>


void DisplayError(HWND hwnd, DWORD dwGle) {

     LPVOID lpMessageBuffer;
     DWORD dwRet;
     
     dwRet = FormatMessage( 
             FORMAT_MESSAGE_ALLOCATE_BUFFER | 
             FORMAT_MESSAGE_FROM_SYSTEM | 
             FORMAT_MESSAGE_IGNORE_INSERTS,
             NULL,
             dwGle,  
             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
             (LPTSTR) &lpMessageBuffer,  
             0,  
             NULL );

     if (dwRet) {

          ::MessageBox (
               hwnd, 
               (LPTSTR) lpMessageBuffer, 
               TEXT("Error"), 
               MB_OK | MB_ICONERROR);

          LocalFree( lpMessageBuffer ); 

     }
     
} 


void GetSid ( HWND hwnd ) {

     TCHAR szName [512];

     Edit_GetText(GetDlgItem(hwnd, IDC_NAMEORSID), szName, 512);

     if ( !_tcslen ( szName ) ) {
          return;
     }

     BOOL bRet;
     BYTE szSidBuff [256];
     PSID pSid = (PSID) szSidBuff;
     DWORD cbSid = sizeof (szSidBuff);
     TCHAR szDomainName [256];
     DWORD cbDomainName = sizeof (szDomainName);
     SID_NAME_USE snUse;
     LPTSTR lpszName;


     lpszName = szName;

     //
     // ユーザーの SID 取得
     //

     // はじめに LookupAccountName API を呼び必要なバッファサイズを得る
     bRet = LookupAccountName (
          NULL, 
          szName, 
          pSid, 
          &cbSid, 
          szDomainName, 
          &cbDomainName, 
          &snUse);
         
     if (!bRet ) {
          DisplayError (hwnd, GetLastError());
          return;
     }
     
     //
     // SID のテキスト表現
     //
     
     LPTSTR pStringSid;
          
     bRet = ConvertSidToStringSid (pSid, &pStringSid);

     if (!bRet) {
          DisplayError (hwnd, GetLastError());
          return;
     }

     Edit_SetText ( GetDlgItem (hwnd, IDC_RESULT), pStringSid);
     
     LocalFree (pStringSid);
     
}


void GetName ( HWND hwnd ) {

     TCHAR szStringSID [256];

     Edit_GetText(GetDlgItem(hwnd, IDC_NAMEORSID), szStringSID, 256);

     if ( !_tcslen ( szStringSID ) ) {
          return;
     }

     BOOL bRet;
     PSID pSid = NULL;
     DWORD cbSid = 0;

     bRet = ConvertStringSidToSid (
          szStringSID,
          &pSid);

     if ( !bRet ) {
          DisplayError (hwnd, GetLastError());
          return;
     }
     
     SID_NAME_USE snu;

     TCHAR szName [256];
     DWORD cbName = sizeof ( szName );
     TCHAR szDomainName [256];
     DWORD cbDomainName = sizeof ( szDomainName );
     
     bRet = LookupAccountSid (
          NULL,
          pSid,
          szName,
          &cbName,
          szDomainName,
          &cbDomainName,
          &snu);

     if ( !bRet ) {
          DisplayError (hwnd, GetLastError());
          return;
     }

     TCHAR szResult [512];
     ::ZeroMemory ( szResult, sizeof (szResult));

     wsprintf (szResult, TEXT("%s"), szDomainName);
     _tcscat ( szResult, TEXT("\\"));
     _tcscat ( szResult, szName);

     
     Edit_SetText ( GetDlgItem (hwnd, IDC_RESULT), szResult);

     LocalFree ( pSid );
     pSid = NULL;
     
}



///////////////////////////////////////////////////////////////////////////////
//
// ダイアログの初期化
//


BOOL OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam) {

     return TRUE;

}


///////////////////////////////////////////////////////////////////////////////
//
// WM_COMMAND メッセージの処理
//


void OnCommand(HWND hWnd, int nID, HWND hWndCtl, UINT codeNotify) {

     switch(nID) {
     case IDC_GETNAME:
          
          GetName ( hWnd );

          break;

     case IDC_GETSID:

          GetSid ( hWnd );

          break;

     case IDCANCEL:

          EndDialog(hWnd, 0);

          break;

     }
}


///////////////////////////////////////////////////////////////////////////////
//
// ウィンドウ (ダイアログ) プロシージャ
//


BOOL CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

     switch(uMsg) {

          HANDLE_MSG(hWnd, WM_INITDIALOG, OnInitDialog);
          HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);

     }

     return FALSE;
}


int APIENTRY WinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPSTR     lpCmdLine,
                      int       nCmdShow ) {

       ::DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, MainWndProc);

     return 0;
}

次の内容を resource.h として保存します。

#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

#define IDD_DIALOG1                             100
#define IDC_NAMEORSID                           1000
#define IDC_RESULT                              1008
#define IDC_GETNAME                             1009
#define IDC_GETSID                              1010

次の内容を resource.rc として保存します。

// Generated by ResEdit 1.4.3
// Copyright (C) 2006-2008
// http://www.resedit.net

#include "resource.h"
#include <windows.h>


//
// Dialog resources
//
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
IDD_DIALOG1 DIALOGEX 0, 0, 247, 72
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_VISIBLE 
| WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
CAPTION "SID Lookup Tool"
FONT 8, "Ms Shell Dlg 2", 400, 0, 1
BEGIN
    EDITTEXT        IDC_NAMEORSID, 5, 5, 222, 12, ES_AUTOHSCROLL
    EDITTEXT        IDC_RESULT, 5, 22, 222, 12, ES_AUTOHSCROLL | ES_READONLY
    PUSHBUTTON      "Name", IDC_GETNAME, 5, 52, 52, 15
    PUSHBUTTON      "SID", IDC_GETSID, 62, 52, 52, 15
END

makefile は以下の通りです。

TARGETNAME=sidlookup
OUTDIR=.\chk

ALL : "$(OUTDIR)\$(TARGETNAME).exe"

"$(OUTDIR)" :
    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"

# compile
CPP_PROJ=\
	/MT\
	/W3\
	/Fo"$(OUTDIR)\\"\
	/Fd"$(OUTDIR)\\"\
	/c\
	/Zi\
	/DWIN32\
	/DUNICODE\
	/D_UNICODE\
	/D_WIN32_WINNT=0x0501


RSC_PROJ=/fo"$(OUTDIR)\$(TARGETNAME).res"

#link
LINK32=link.exe

LINK32_FLAGS=\
	user32.lib\
	advapi32.lib\
	/subsystem:windows\
	/pdb:"$(OUTDIR)\$(TARGETNAME).pdb"\
	/machine:I386\
	/out:"$(OUTDIR)\$(TARGETNAME).exe"\
	/DEBUG\
	/RELEASE
	
LINK32_OBJS= \
	"$(OUTDIR)\$(TARGETNAME).obj" "$(OUTDIR)\$(TARGETNAME).res"

"$(OUTDIR)\$(TARGETNAME).exe" : "$(OUTDIR)" $(LINK32_OBJS)
    $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)


.cpp{$(OUTDIR)}.obj:
   $(CPP) $(CPP_PROJ) $< 


"$(OUTDIR)\sidlookup.res": resource.rc
	rc.exe $(RSC_PROJ) resource.rc

以上を nmake すると、サブディレクトリ chk に sidlookup.exe が作られます。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説