フォルダアクセス権取得について


ん?  2009-10-30 19:41:20  No: 36022

フォルダのアクセス権について(2006/06/02)
https://www.petitmonte.com/bbs/answers?question_id=4002

これの続きです( もう3年も前の話で、とても古いけど)

ママんさんのコードがだめだったのは、参照したいフォルダに新たに設定された
アクセス許可エントリしか取得できず、上位フォルダから継承されたもアクセス
許可エントリが取得できなかったため。
GetNamedSecurityInfo の引数を変えてやれば取得できたかもしれませんが、
今回Vista の UAC対策に、もうちょっと突っ込んでやってみました。

※ 今回、特に参考にした資料
フォルダのアクセス権チェック方法について
http://social.msdn.microsoft.com/forums/ja-JP/vcgeneralja/thread/a4225c57-ebc3-4808-8464-dc731548ab99/

アクセスコントロール / アクセスチェック
http://eternalwindows.jp/security/accesscontrol/accesscontrol04.html

主な宣言
var
  hToken,
  hTokenImpersonatation:THandle;
  dwTokenUserLength: DWORD;
  pTokenUser: ^TSIDAndAttributes;
  pSecurityDescriptor: PSECURITY_DESCRIPTOR;
  pDACL: PACL;

細かいとこはSDKとか読んでください。
また、NT系のみ、2000以降のみとかAPIも使っているかもしれませんが、
それもSDKとかで確認してください。

1) GetVolumeInformationを使って NTFS か判定する。
  これは、上記の質問内にコードが含まれています。

2) GetNamedSecurityInfo を使用して、セキュリティ記述子を取得する
  if GetNamedSecurityInfo(PChar("調査フォルダ"),
      SE_FILE_OBJECT,    
      OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION or 
      DACL_SECURITY_INFORMATION,  // 取得するセキュリティ情報のタイプ
      nil, nil, @pDACL,  nil,
      pSecurityDescriptor) = 0 then //成功

3) 自プロセスのトークンを取得する
  NT, 2000, XP とかなら、フォルダのアクセス権がそのまま、自分のアクセス権に
  なりますが、VistaのUACの存在が、ユーザー権限で動作を行うため、アカウントの
  アクセス権では判定できないのです(たぶん)。
  OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY or TOKEN_DUPLICATE, htoken)

4) トークン情報を取得する
  「AccessCheckに指定するトークンは偽装トークンでなければならないため」
  (By 参考資料に二つ目のリンクより一部抜粋)
  ということで、トークンを取得して、偽装トークンに複製する必要があります。
  そのための準備
  //1回目で情報のサイズを取得し
  GetTokenInformation(hToken, TokenUser, nil, 0, dwTokenUserLength);
  //メモリ確保
  pTokenUser := GetMemory(dwTokenUserLength)
  //ここで本当にトークン情報を取得する
  GetTokenInformation(hToken, TokenUser, pTokenUser, 
    dwTokenUserLength, dwTokenUserLength);

5) 偽装トークンに複製
  DuplicateTokenEx(hToken, GENERIC_ALL, nil, SecurityImpersonation,
      TokenImpersonation, hTokenImpersonatation)

6) アクセス許可の判定

{アクセス権の調査}
var
  genericMapping: TGenericMapping;
  dwDesiredAccess: Cardinal;
  dwSize: Cardinal;
  privilegeSet: TPrivilegeSet;
  dwGrantedAccess: DWORD;
  accessStatus: LongBool;
begin
  {初期化}
  FillChar(genericMapping, SizeOf(TGenericMapping), 0);

  //この FILE_GENERIC_READ, FILE_GENERIC_WRITE 定数については
  //Delphiのユニットには含まれていない可能性が高いので
  //Googleさんなどで検索してくださいな

//読み込み可能であるか調べる場合
  //dwDesiredAccess := FILE_GENERIC_READ;
  //書き込み可能であるか調べる場合
  dwDesiredAccess := FILE_GENERIC_WRITE;

  {調査するアクセス権のマッピングを用意}
  genericMapping.GenericRead := FILE_GENERIC_READ;
  genericMapping.GenericWrite := FILE_GENERIC_WRITE;
  genericMapping.GenericExecute := FILE_GENERIC_EXECUTE;
  genericMapping.GenericAll := FILE_ALL_ACCESS;
  {アクセスマスク内の汎用のアクセス権を、特定の標準的なアクセス権にマップする}
  MapGenericMask(dwDesiredAccess, genericMapping);

  {初期化}
  dwSize := SizeOf(PRIVILEGE_SET);

  privilegeSet.PrivilegeCount := 0;
  {アクセス トークンによって識別されたクライアントに対して、
   指定されたアクセス権利セットを、セキュリティ記述子が許可しているか
   どうかを調べます。通常、サーバーアプリケーションはこの関数を使って、
   プライベートオブジェクトへのアクセスを確認します。}
  if AccessCheck(pSecurityDescriptor, hTokenImpersonatation, 
    dwDesiredAccess, genericMapping, privilegeSet, dwSize,
    dwGrantedAccess, accessStatus) then begin
    if accessStatus then //アクセス許可されています
    else  //アクセス許可されていません
  end
  else begin
    //アクセス権の取得に失敗
  end;
end;

以上で、Vista,Sevenでも、UACが有効で、ユーザー権限で動作中のアクセス権と、
admin権限での動作のアクセス権が判定できると思います。

一応、XP SP2、Vista UAC オンの通常起動、Vista UAC オンのadmin権限起動で
フォントフォルダのアクセス権の判定がうまくいっています。

ソースを完全掲載じゃないので、足りないトコは自分で調べてください m(v_v)m


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加