EternalWindows
アカウント管理 / SIDの作成

これまで述べてきたように、特定のアカウントのSIDを取得したい場合は、 そのアカウントの名前をLookupAccountNameに指定することができます。 ただし、システムに予め存在することが分かっているアカウントのSIDを取得したい場合は、 このように名前からSIDへの変換を行う必要はありません。 固定したSIDの値に注目して、その値を基にSIDを作成することができるからです。 次に示すアカウントはビルトイングループと呼ばれ、 どのようなシステムにも必ず存在するはずです。

SID 名前 説明
S-1-5-32-544 Administrators システム内のほとんどのオブジェクトにアクセスできるが、 特権が必要となる作業では、事前に特権を割り当てる必要がある。 既定では、Administratorアカウントが属する。
S-1-5-32-545 Users Administratorsと比べて、アクセスが許可されているオブジェクトが少ない。 たとえば、C:\やC:\Program Filesへの書き込みアクセスは失敗する。 また、割り当てられている特権も、Administratorsに比べて少ない。 標準ユーザーがこのグループに属するが、トークン上ではAdministratorsやGuestsも属している。
S-1-5-32-546 Guests Usersグループと同等の権限を持つ。 このグループに属するユーザーがデスクトップに加えた変更は、 ログオフの際に破棄される。 既定では、Guestアカウントが属する。

このようなSIDは、サブ機関値の値がどのようなシステムでも固定であるため、 この値を理解しておくことで、SIDを作成することができるようになります。 次に示すアカウントは、サービスアプリケーションに割り当てられるサービスアカウントですが、 これらのアカウントのSIDも固定されています。

SID 名前 説明
S-1-5-18 SYSTEM 一般のサービスアプリケーションやシステムプロセスのアカウント。 起動時から数多くの特権が有効になっており、 そのシステムにおいて完全なアクセスが可能。
S-1-5-19 LOCAL SERVICE サービス用のアカウント。 Usersグループと同等の権限を持つ。 ネットワークリソースへのアクセスは匿名アカウントを使用する。
S-1-5-20 NETWORK SERVICE サービス用のアカウント。 Usersグループと同等の権限を持つ。 ネットワークリソースへのアクセスはコンピュータアカウントを使用する。

たとえば、タスクマネージャを起動してみると、 これらのアカウントで動作するプログラムが存在することが確認できます。

数値を基にSIDを作成する場合は、AllocateAndInitializeSidを呼び出します。

BOOL WINAPI AllocateAndInitializeSid(
  PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
  BYTE nSubAuthorityCount,
  DWORD dwSubAuthority0,
  DWORD dwSubAuthority1,
  DWORD dwSubAuthority2,
  DWORD dwSubAuthority3,
  DWORD dwSubAuthority4,
  DWORD dwSubAuthority5,
  DWORD dwSubAuthority6,
  DWORD dwSubAuthority7,
  PSID *pSid
);

pIdentifierAuthorityは、SIDの識別子機関値を格納したSID_IDENTIFIER_AUTHORITY構造体のアドレスを指定します。 nSubAuthorityCountは、SIDのサブ機関値の数を指定します。 dwSubAuthority0からdwSubAuthority7は、サブ機関値と設定する値を指定します。 たとえば、nSubAuthorityCountに2を指定したならば、dwSubAuthority0とdwSubAuthority1を初期化します。 pSidは、作成されたSIDを受け取る変数のアドレスを指定します。

AllocateAndInitializeSidで作成されたSIDは、FreeSidで開放することになります。

PVOID WINAPI FreeSid(
  PSID pSid
);

pSidは、開放したいSIDを指定します。

通常、数値でSIDを作成する場合はAllocateAndInitializeSidを呼び出しますが、 SID構造体を明示的に初期化することでも、SIDを作成することができます。 次に、SID構造体の定義を示します。

typedef struct _SID {
   BYTE  Revision;
   BYTE  SubAuthorityCount;
   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
   DWORD SubAuthority[ANYSIZE_ARRAY];
} SID, *PISID;

Revisionは、リビジョン番号を指定します。 SubAuthorityCountは、サブ機関値の数を指定します。 IdentifierAuthorityは、識別子機関値を指定します。 SubAuthorityは、サブ機関値を指定します。 ANYSIZE_ARRAYは、メンバが配列を表すための指標であり、実際には1として定義されています。 よって、サブ機関値を2つ以上持つSIDは、SID構造体を可変長のバッファとして扱います。

今回のプログラムは、SYSTEMとAdministratorsのSIDを作成する例を示しています。

#include <windows.h>
#include <sddl.h>

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	SID                      sidSystem = {1, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID};
	PSID                     pSidAdministrators;
	LPTSTR                   lpszSystemSid;
	LPTSTR                   lpszAdministratorsSid;
	SID_IDENTIFIER_AUTHORITY sidIdentifier = SECURITY_NT_AUTHORITY;
	
	AllocateAndInitializeSid(&sidIdentifier, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
		0, 0, 0, 0, 0, 0, &pSidAdministrators);
	
	ConvertSidToStringSid(&sidSystem, &lpszSystemSid);
	ConvertSidToStringSid(pSidAdministrators, &lpszAdministratorsSid);

	MessageBox(NULL, lpszSystemSid, TEXT("SYSTEM"), MB_OK);
	MessageBox(NULL, lpszAdministratorsSid, TEXT("Administrators"), MB_OK);

	LocalFree(lpszSystemSid);
	LocalFree(lpszAdministratorsSid);
	
	FreeSid(pSidAdministrators);

	return 0;
}

このプログラムでは、SYSTEMのSIDをSID構造体で初期化し、 AdministratorsのSIDをAllocateAndInitializeSidで作成しています。 まずは、SID構造体の初期化を確認します。

SID sidSystem = {1, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID};

SID構造体の最初のメンバはリビジョン番号であり、これは1になります。 2番目のメンバはサブ機関値の数であり、SYSTEMのSIDは1つであるため、1を指定しています。 3番目のメンバは識別子機関値であり、SYSTEMのSIDは5になっているため、 5を表すSECURITY_NT_AUTHORITYを指定しています。 4番目のメンバはサブ機関値であり、SYSTEMのSIDは18になっているため、 18を表すSECURITY_LOCAL_SYSTEM_RIDを指定します。

AdministratorsのSIDは、AllocateAndInitializeSidで作成されています。

SID_IDENTIFIER_AUTHORITY sidIdentifier = SECURITY_NT_AUTHORITY;

AllocateAndInitializeSid(&sidIdentifier, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
	0, 0, 0, 0, 0, 0, &pSidAdministrators);

第1引数は、識別子機関値を格納した変数のアドレスを指定します。 AdministratorsのSIDは識別子機関値が5であるため、SECURITY_NT_AUTHORITYを指定します。 第2引数は、サブ機関値の数を指定します。 AdministratorsのSIDは2つ存在するため、2を指定します。 第3引数は、最初のサブ機関値を指定します。 AdministratorsのSIDでは32になっているため、これを表すSECURITY_BUILTIN_DOMAIN_RIDを指定します。 AdministratorsのSIDの2番目のサブ機関値は544であるため、 これを表すDOMAIN_ALIAS_RID_ADMINSを指定します。 これで2つのサブ機関値を指定したことになりますから、 残りのサブ機関値の引数には0を指定しても問題ありません。

既知のSIDについて

WindowsXPでは、CreateWellKnownSidという既知のSIDを作成する関数が登場しました。 既知のSIDとは、どのようなシステムにも存在するSIDのことであり、 今回取り上げたビルトイングループやサービスアカウントのSIDも、 この既知のSIDに含まれます。 CreateWellKnownSidでは、専用の定数を指定するだけでSIDを作成することができるため、 今回のように作成するSIDのサブ機関値を事前に把握しておく必要はなくなります。 次に、例を示します。

#include <windows.h>
#include <sddl.h>

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	PSID   pSid;
	DWORD  dwSidSize;
	LPTSTR lpszSid;

	dwSidSize = SECURITY_MAX_SID_SIZE;
	pSid = (PSID)LocalAlloc(LPTR, dwSidSize);
	CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, pSid, &dwSidSize);

	ConvertSidToStringSid(pSid, &lpszSid);
	MessageBox(NULL, lpszSid, TEXT("Administrators"), MB_OK);

	LocalFree(lpszSid);
	LocalFree(pSid);

	return 0;
}

この例では、CreateWellKnownSidの第1引数にWinBuiltinAdministratorsSidを指定しています。 このような定数を指定するだけで、第3引数にAdministratorsのSIDが返ることになります。 SIDが既知のSIDであるかを確認したい場合は、IsWellKnownSidを呼び出します。

既知のSIDには、AdministratorのようなビルトインアカウントのSIDも含まれていますが、 このようなSIDはコンピュータのSIDをベースとしています。 よって、こうしたアカウントのSIDを取得したい場合は、 第2引数にコンピュータのSIDを指定する必要があります。

CreateWellKnownSid(WinAccountAdministratorSid, pSidComputer, pSidAdministrator, &dwSidSize);

第1引数にAdministratorのSIDを取得することを示すWinAccountAdministratorSidを指定しています。 この場合は、コンピュータのSIDを第2引数に指定することになります。



戻る