none
フォルダのアクセス権チェック方法について RRS feed

  • 質問

  • お世話になります。JABX2です。

     

    現在、プロセスを起動しているアカウントが指定されたフォルダに対して

    「フォルダが存在するか?」、「フォルダが読取&書込可能であるか?否か?」を

    以下の方法により行っています。

     

    Code Snippet

    HANDLE hFolder = CreateFile(
           cstrTargetFolder,
           GENERIC_READ | GENERIC_WRITE,
           FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
           NULL,
           OPEN_EXISTING,
           FILE_FLAG_BACKUP_SEMANTICS,
           NULL
          );

     

    if(INVALID_HANDLE_VALUE == hFolder)
    {
     //①存在しない or 読取&書込不可
     ...
    }
    else
    {
     //②読取&書込許可
     CloseHandle(hFolder);
     ...
    }

     

     

    期待値としては、現在のプロセスがそのフォルダの読取&書込が行えない場合、

    ①を通過、読取&書込が行える場合、②を通過することを期待しています。

     

    そこで、WinXP Home/Pro でAdministratorsグループに属するアカウントのユーザが

    作成したフォルダA(アクセス権の変更はしない)へUsersグループに属するアカウントの

    ユーザがエクスプローラからフォルダAへファイルの読取&書込ができますが、

    上記では①を通過してしまい、期待した動作となりません。

     

    理由としては、管理者アカウントで作成したフォルダAに対する、制限付アカウントの

    アクセス権はフォルダAの[プロパティ]-[セキュリティ]タブ-[Users のアクセス許可]の

    リストで[許可]のチェックが付いているのは、

      ・読み取りと実行

      ・フォルダ内容の一覧表示

      ・読み取り

      ・特殊なアクセス許可

    で、エクスプローラからフォルダAに書込みができるのは、特殊なアクセス許可において、

      ・ファイルの作成/データの書き込み

      ・フォルダの作成/データの追加

    にチェックが付いているためであり、CreateFile ではこれを識別できず①を通過する。

    [Users のアクセス許可]の

      ・書き込み

    にチェックが付いていると CreateFile でも書込できると認識でき②を通過するためです。

     

    長くなりましたが、CreateFile 関数でフォルダの存在&読取/書込可否チェックを行うのは

    妥当ではないのでしょうか?

    ※結果を見れば妥当ではないと思いますが....

    フォルダの読取/書込可否チェックはどのように行うのが一般的なのでしょうか。

    ※フォルダを直接読取&書込を行う以外で

     

    ご存知の方、何卒ご教授いただきたくお願いいたします。

    2008年8月12日 13:43

回答

  • iversonjpです。

    実際に試してないので憶測で答えていますのでご了承ください。

    質問の要求というのは、

    1.フォルダが存在するか?存在しない場合エラー(?)とする。
    2.フォルダが存在する場合、フォルダ配下にフォルダ/ファイルの作成、および読み取り、変更ができるか?

    ということですよね?
    以後上記要求であると認識して話させていただきます。


    UPされているソースでは、そのフォルダ自身に読込み、書き込みでオープンできるか?
    という意味に見えるので要求と少し違っている気がします。

    試しに、エクスプローラ上でUsersグループのユーザは、
    そのフォルダの名前を変更できますでしょうか?
    CreateFile に WRITE を付けてフォルダをオープンすると
    どんな状態なのかはちょっとわかりませんが、憶測ではこのような状況では?と考えます。

     JABX2 さんからの引用

    ※フォルダを直接読取&書込を行う以外で



    これは、そのフォルダ内に試しにファイルを作成してみる方法以外でと考えてよろしいでしょうか?
    楽なのは、実際にテンポラリファイルを一度作成してみるのが一番早いような気がします。

    また、厳密にアクセス権を調べたいのでしたら、
    ACL系の操作をして、実際のアクセス権を取得して調べるのが確実だと思います。

    的をはずしていたらごめんなさい。。


    2008年8月13日 14:01
  •  iversionjp さんからの引用
    これは、そのフォルダ内に試しにファイルを作成してみる方法以外でと考えてよろしいでしょうか?
    楽なのは、実際にテンポラリファイルを一度作成してみるのが一番早いような気がします。


    私もそう思います。

    というより、そもそもチェックをする必要があるのでしょうか?
    何らかのデータをファイルとして保存したいなら、書き込めるかどうかをチェックせずにいきなり書き込んでしまえば良いのではないでしょうか。
    ファイルを作成してみて失敗したら、そこで初めてエラー処理をする、というと乱暴な感じがするかも知れませんが、例えば書き込み権限を外したフォルダにメモ帳でファイルを保存してみれば、まさにこのような処理になっていることが分かるはずです。

    どうしても調べたい場合は API 群が用意されています……が、そこまでしたいかどうかを再検討する価値はあるでしょう。
    (幸い、私は必要に迫られたことはありませんが、多分 GetFileSecurity あたりから攻めるのではないかと思います。)
    http://msdn.microsoft.com/en-us/library/aa375742(VS.85).aspx

    そして、仮にこれらの API を駆使してフォルダのアクセス権が得られたとしても、アクセス権の取得は拒否するが書き込みは許可するなんていう変態フォルダには対処できないはずです。

    2008年8月14日 2:09

すべての返信

  • iversonjpです。

    実際に試してないので憶測で答えていますのでご了承ください。

    質問の要求というのは、

    1.フォルダが存在するか?存在しない場合エラー(?)とする。
    2.フォルダが存在する場合、フォルダ配下にフォルダ/ファイルの作成、および読み取り、変更ができるか?

    ということですよね?
    以後上記要求であると認識して話させていただきます。


    UPされているソースでは、そのフォルダ自身に読込み、書き込みでオープンできるか?
    という意味に見えるので要求と少し違っている気がします。

    試しに、エクスプローラ上でUsersグループのユーザは、
    そのフォルダの名前を変更できますでしょうか?
    CreateFile に WRITE を付けてフォルダをオープンすると
    どんな状態なのかはちょっとわかりませんが、憶測ではこのような状況では?と考えます。

     JABX2 さんからの引用

    ※フォルダを直接読取&書込を行う以外で



    これは、そのフォルダ内に試しにファイルを作成してみる方法以外でと考えてよろしいでしょうか?
    楽なのは、実際にテンポラリファイルを一度作成してみるのが一番早いような気がします。

    また、厳密にアクセス権を調べたいのでしたら、
    ACL系の操作をして、実際のアクセス権を取得して調べるのが確実だと思います。

    的をはずしていたらごめんなさい。。


    2008年8月13日 14:01
  •  iversionjp さんからの引用
    これは、そのフォルダ内に試しにファイルを作成してみる方法以外でと考えてよろしいでしょうか?
    楽なのは、実際にテンポラリファイルを一度作成してみるのが一番早いような気がします。


    私もそう思います。

    というより、そもそもチェックをする必要があるのでしょうか?
    何らかのデータをファイルとして保存したいなら、書き込めるかどうかをチェックせずにいきなり書き込んでしまえば良いのではないでしょうか。
    ファイルを作成してみて失敗したら、そこで初めてエラー処理をする、というと乱暴な感じがするかも知れませんが、例えば書き込み権限を外したフォルダにメモ帳でファイルを保存してみれば、まさにこのような処理になっていることが分かるはずです。

    どうしても調べたい場合は API 群が用意されています……が、そこまでしたいかどうかを再検討する価値はあるでしょう。
    (幸い、私は必要に迫られたことはありませんが、多分 GetFileSecurity あたりから攻めるのではないかと思います。)
    http://msdn.microsoft.com/en-us/library/aa375742(VS.85).aspx

    そして、仮にこれらの API を駆使してフォルダのアクセス権が得られたとしても、アクセス権の取得は拒否するが書き込みは許可するなんていう変態フォルダには対処できないはずです。

    2008年8月14日 2:09
  • こんにちは。中川俊輔 です。

     

    iversionjpさん、zakioさん、回答ありがとうございます。

     

    JABX2さん、フォーラムのご利用ありがとうございます。

    その後いかがでしょうか?

    有用な情報と思われたため、

    iversionjpさん、zakioさんの回答へ回答済みチェックをつけさせていただきました。

    追加の質問等おありましたら、是非投稿してみてください

     

    回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
    有用な情報と思われる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。

    JABX2さんはチェックを解除することもできますので、ご確認ください。

     

    それでは!

    2008年8月27日 8:27
  •  

    iversonjp 様、zakio 様

     

    お返事が遅くなりまして申し訳ありません。

     

    お二人からのご回答から ACL 系の API で実装することにしまして、

    いろいろと調べながらなんとか実装をしました。

     

    以下のように実装しました。

     

    1.GetNamedSecurityInfo で対象フォルダのセキュリティ記述子を取得

    2.GetUserName で現在のスレッドのユーザー名(アカウント)を取得

      ※私の環境だけなのかもしれませんが Vista の場合、GetUserName 関数を

        1度しか呼出さない場合、関数はTRUEを返却しますが、第一引数にユーザ名

        (アカウント)を示す文字列が格納されません。

        2回呼出すと2回目の方では期待したユーザ名(アカウント)の文字列が格納

        されています。。。

    3.BuildTrusteeWithName で上記2.で取得したユーザ名で TRUSTEE 構造体を初期化

    4.GetEffectiveRightsFromAcl で上記3.のトラスティに対する上記1.の対象フォルダの

      アクセス権を取得(※)

      ※ユーザ名(アカウント)が所属するグループも含め全てのアクセス許可/拒否の

        情報を取得することができます。

    5.上記4.で得られた結果で必要なアクセス権が付与されているかチェックする

     

    ただ、上記のコードの場合 Vista で動作させると、当たり前のことなんですが

    XP/2000と同じ結果が返却されます。

    しかし、Vista では、プロセスは通常は標準ユーザで動作しているため、

    例えば、Users グループの権限には"書込み"がない場合、本来は

    「アクセス拒否」と判定したいのですが、Administrators グループの権限で

    "書込み"が含まれていると「アクセス許可」となってしまいます。

     

    そこで、現在のプロセスに対するフォルダのアクセス権を取得するための

    ACL 系の API をご存知の方がいらっしゃいませんでしょうか。

    2008年9月12日 2:17