EternalWindows
アクセスコントロール / SDDL

SDDL(Security Descriptor Definition Language)は、 セキュリティ記述子を文字列で表すように定義されたフォーマットです。 文字列をSDDLのフォーマットに従って構成すれば、 その文字列は所有者SIDやDACLを表していることになります。 DACLを表すSDDLのフォーマットは次のようになります。

"D:DACLフラグ(ACE文字列1)(ACE文字列2)・・・(ACE文字列n)"
例) "D:P(A;;GA;;;BA)"

例に記されている文字列が正にDACLを表しており、 個々の文字はフォーマットに準拠しています。 SDDLでDACLを表現するときは文字列の先頭にDを付け、その後に:を付けます。 次の文字は、DACLフラグであり、例ではPとなっています。 DACLフラグが取り得る文字列は以下のようになります。

文字列 フラグ 意味
"P" SE_DACL_PROTECTED DACLが継承ACEで構成されるのを抑制する。
"AR" SE_DACL_AUTO_INHERIT_REQ DACLをリーフオブジェクトに継承することを示す。
"AR" SDDL_AUTO_INHERITED このDACLが継承ACEで構成されていることを示す。

このフラグは、SECURITY_DESCRIPTOR構造体のControlメンバに対応します。 続いてACE文字列のフォーマットを見てみましょう。

(ACEタイプ;ACEフラグ;権限;オブジェクトGUID;継承オブジェクトGUID;アカウントSID)
例) (A;;GA;;;BA)

ACE文字列は括弧でくくり、括弧の数はACEの数に比例します。 フォーマットは、ACEの各要素を;で区切って指定するという単純なものです。 ACEタイプは、ACEがアクセス許可かアクセス拒否かどうかを表します。 Aはアクセス許可、Dならばアクセス拒否の意味です。 フラグは継承フラグのことで、コンテナオブジェクトを作成するときは重要になります。

文字列 フラグ
"CI" CONTAINER_INHERIT_ACE
"OI" OBJECT_INHERIT_ACE
"ID" INHERITED_ACE

権限はアクセスマスクのことです。

文字列 権限
"GA" GENERIC_ALL
"GR" GENERIC_READ
"GW" GENERIC_WRITE
"GX" GENERIC_EXECUTE
"RC" READ_CONTROL
"SD" DELETE
"WD" WRITE_DAC
"WO" WRITE_OWNER

たとえば、GENERIC_READとGENERIC_EXECUTEの組み合わせの場合はGRGXとなります。

オブジェクトGUIDと継承オブジェクトGUIDはActiveDirectoryで使われるため、 多くの場合は省略されます(文字列を省略するときは;だけ書きます)。

アカウントSIDは、アクセス許可または拒否の判定となるアカウントのSIDです。 ここには、アカウントのテキスト形式のSIDを設定することもできますが、 Administratorsのようなビルトイングループを対象とする場合には、 専用の定義を利用したほうがよいでしょう。

文字列 SID
"BA" Administrators
"BU" Users
"BG" Guests
"SY" SYSTEM

これらを基に、先に示したACE文字列を解釈してみましょう。 まず、Aという文字からACEがアクセス許可ACEだということが分かります。 続いてフラグの部分が;だけになっています。 これは、継承フラグを持たないということを意味しています。 権限ではGAとなっており、GENERIC_ALLを意味しています。 UUIDの2つは設定していないため、;だけとなっています。 最後のSIDはBUつまり、Usersのことを意味しています。 よって、このACEはUsersに全てのアクセスを許可するということが分かります。

SSDL文字列からセキュリティ記述子を取得するには、 ConvertStringSecurityDescriptorToSecurityDescriptorを呼び出します。

BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptor(
  LPCTSTR StringSecurityDescriptor,
  DWORD StringSDRevision,
  PSECURITY_DESCRIPTOR *SecurityDescriptor,
  PULONG SecurityDescriptorSize
);

StringSecurityDescriptorは、SDDL文字列を指定します。 StringSDRevisionは、SDDL_REVISION_1を指定します。 SecurityDescriptorは、セキュリティ記述子を受け取る変数のアドレスを指定します。 このセキュリティ記述子は、自己相対形式です。 SecurityDescriptorSizeは、SecurityDescriptorのサイズを受け取る変数のアドレスを指定します。 不要な場合はNULLを指定しますが、セキュリティ記述子を保存したいような場合はサイズを取得する必要があります。

今回のプログラムは、SDD文字列からセキュリティ記述子を作成し、これをファイルに指定します。 ConvertStringSecurityDescriptorToSecurityDescriptorの呼び出すには、 sddl.hのインクルードが必要になります。

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

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	HANDLE               hFile;
	LPTSTR               lpszSddl = TEXT("D:P(A;;GA;;;BU)");
	SECURITY_ATTRIBUTES  securityAttributes;
	PSECURITY_DESCRIPTOR pSecurityDescriptor;

	ConvertStringSecurityDescriptorToSecurityDescriptor(lpszSddl, SDDL_REVISION_1, &pSecurityDescriptor, NULL);

	securityAttributes.nLength              = sizeof(SECURITY_ATTRIBUTES);
	securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
	securityAttributes.bInheritHandle       = FALSE;

	hFile = CreateFile(TEXT("sample.txt"), GENERIC_WRITE, 0, &securityAttributes, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		MessageBox(NULL, TEXT("ファイルの作成に失敗しました。"), NULL, MB_ICONWARNING);
		LocalFree(pSecurityDescriptor);
		return 0;
	}

	MessageBox(NULL, TEXT("ファイルを作成しました。"), TEXT("OK"), MB_OK);
	
	LocalFree(pSecurityDescriptor);
	CloseHandle(hFile);
	
	return 0;
}

lpszSddlがSDDL文字列を表しています。 これをConvertStringSecurityDescriptorToSecurityDescriptorに指定すれば、 第3引数にセキュリティ記述子が返ることになります。 後は取得したセキュリティ記述子をSECURITY_ATTRIBUTES構造体のlpSecurityDescriptorメンバに指定し、 CreateFileにSECURITY_ATTRIBUTES構造体を指定します。 これにより、作成されたファイルのDACLは、lpszSddlを反映したものになります。


戻る