フォルダ内のファイルの書き込み・作成が出来るかどうかのチェック

[戻る]
たろ 2009/04/01(水) 22:55:01
APIのAccessCheckにて
フォルダ内のファイルの作成や書き込みが出来るかどうか
チェックを行いたいと考えていたのですが
例えば VistaのUACがオンの時には、 C:\(ルート)※1 を指定した場合
最後の引数(第8引数)でTRUEが入ってくるにも関わらず、 
自分で作成した以下に示すようなMFCのプログラム※2からはファイルの作成が失敗して
しまう
という状態で、 どのようにしたらよいか困り果てています。
(AccessCheckはそもそも読み書きが出来るかどうかだけ判断するAPIなのかもしれない
が、)


ダミーでファイル作成を行いそのエラーで判断したりするのではなく
XPでもVistaでも正しくファイルの作成・書き込みが出来るかどうかを
チェックする方法はないでしょうか?


※1 以下の2パターンで取得
GetNamedSecurityInfo("フルパスファイル名", SE_FILE_OBJECT, 
DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | 
GROUP_SECURITY_INFORMATION, ...略);

GetFileSecurity("フルパスファイル名", DACL_SECURITY_INFORMATION | 
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, 略);


※2
CFile fi;
fi.Open(L"c:\\test.txt", CFile::modeCreate | CFile::modeWrite);
fi.Close();
ファイルの作成に失敗するのだから それを前もって知りたい

tetrapod 2009/04/02(木) 08:33:43
チェックしたその瞬間にはアクセス許可が[あって/なくて]
その結果に基づき、目的のファイルを作成や読み書きしようとした
まさにその瞬間にはアクセス許可が[取り消されて/追加されて]
いる、というのは現代マルチタスク・マルチユーザOSではごく普通の話なので

「事前チェックを行うこと自体が原理的に無駄」

なわけだ。俺なら事前チェックはしない。考えるだけ無駄だと思う。

たろ 2009/04/02(木) 14:03:34
そうですね、 俺もそう思います。
ですが仕様ですので、
どうにかならないものかと悩んでいる状態です。
セキュリティディスクリプタを直に読んでいくというのも
すんごく難しそうな気がするのですが、
サンプルとかすら見つけられないでいます。

とりあえず、
作業フォルダを設定する時にファイル作成や、 書き込みが出来ないフォルダ
であれば[書き込みが出来ないフォルダ]であることを知らせることができ、
もしこの設定後に フォルダのアクセス権がなくなるようなことがあった場合
そうそうあることではないと思いますし、
その時は書き込み時にエラーとするということになるかと思います。

tetrapod 2009/04/02(木) 14:46:54
フロッピーディスクや USB ディスクや SD メモリディスクな場合、
ユーザーの権限として書き込みができるかどうかをチェックしても結局無駄で
最終的にプロテクトノッチが禁止になっているかどうかは
実際に書き込んでみないとわからないですよ。

> ダミーでファイル作成を行いそのエラーで判断
しかない、と思うわけだが。

原理的に無駄な仕様ならば採用しなけりゃいいわけで
仕様ですから しょうがないではなくて
その仕様、意味ないですよ、変えませんか?
とその種の権限を持つ人に働きかける方向に動く気は無いですか。
そうですか。

たろ 2009/04/02(木) 17:47:19
>実際に書き込んでみないとわからないですよ。
やっぱりそうなんですね。
であれば、 DeviceIOControlで指定するCreateFileのハンドルに
【\\.\ドライブ名:】や、【\\.\PHYSICALDRIVEx】
を指定する時のように実際にファイルやフォルダ等後に残るものを作ることなく
フォルダにファイルが作成できるかどうかを判断する方法を
ご存じないでしょうか?


>とその種の権限を持つ人に働きかける方向に動く気は無いですか。
いえ、最初に仕様を決める段階ではあまり意味がないのでやめませんか。
という方向で話はしましたよ、
ですが、 書き込みが出来ないものは選択できないようにしてほしい
とのことだったので やむなしです。
(ログフォルダをフォルダ選択ツリーなどを使って指定するときのように
選択したフォルダにプログラムが自動でファイルを作成、書き込みしていくので
書き込めないフォルダを指定してもしょうがないから選択決定時に
そのフォルダが書き込み禁止であるならそのことを知らせてもらえると
使いやすいし、 分かりやすいとのこと)

ryo 2009/04/02(木) 18:04:49
後を残したくないなら実際に書いてみて、すぐに消せばいい

フォルダのプロパティの属性だとか管理者権限とか確認しても
実際にはそれ通りに動かないこともあるし
実際に書き込む以上に正しい情報は得られる方法はないでしょう

たろ 2009/04/02(木) 18:18:00
すばやい回答ありがとうございます。
>後を残したくないなら実際に書いてみて、すぐに消せばいい
出来るだけこれをやりたくないと思って色々調べていたんですが
やっぱりこれしかないってことなんですよね?
(万が一、強制終了した時とかにごみファイルが残ってしまう可能性がある為)

技術的にこれしか方法がないということであれば
了承も取れるであろうし、それまでの話なんですが
それが分からず アクセス権やら、プロテクトチェックだの難しい
情報に振り回されて行き詰っていました。

Ban 2009/04/02(木) 22:31:39
> (万が一、強制終了した時とかにごみファイルが残ってしまう可能性がある為)

Write Onlyとかでも一緒ですね。

ケーブル抜けのほか、ダミーファイルも本物と同等のサイズで書かないと、
「本物はディスク容量不足で書き込みに失敗する」とかもあるでしょうし、
大物の場合、同じサイズで書くのも無駄でしょうし…。

結局、「選んだ結果、書き込みに失敗することがあります」は消せないので、
ファイルが残る可能性があるくらいなら、実際に書き込んでみるのは
止めてしまうのも手だと思います。

どうせ完全でないと分かっている上でのガードならば、
権限で明らかに書き込みできないものだけ判断するとか
「明らかにかけないと分かっているもの」だけ検出する。

--
ログフォルダ設定時に書き込みの可否が気になるというのも分からなくはないです。
いっそ(もし本当にログなら)『「ログフォルダを変更した」というログを書き込む』と
か。
「本物のデータを書く」なら消さずに済みますから。
# でも明らかに「テストラン」を考えた方がいい気がしますが。

..... 2009/04/03(金) 09:22:22
テンポラリーファイルなら、後の事は考えなくても良かった様な。。

aetos 2009/04/03(金) 09:58:33
CreateFile を FILE_FLAG_DELETE_ON_CLOSE 付きで使うとか。
絶対とは言えませんが、いくらかは確実&楽になるかも。

! 2009/04/03(金) 11:34:36
あとで書けなくなったときにエラーメッセージで済ませられるくらいなら、
今、テンポラリファイルが削除できなかった場合だってエラーメッセージで
済ませてしまっていい、ということはないかしら?

書き込み検査用に作成したファイルが削除できませんでした。
お手数ですが手動で削除してください。
ファイル名:xxxx

実際には滅多にお目にかかるエラーではないと思いますけど。
#ライフサイクル終えるまで誰も遭遇しないかも。

たろ 2009/04/03(金) 11:38:37
>どうせ完全でないと分かっている上でのガードならば、
>権限で明らかに書き込みできないものだけ判断するとか
>「明らかにかけないと分かっているもの」だけ検出する。
そうですね。 完全でないと分かっている上でのガードとして
メディアのプロテクトとか読み取り専用のCDみたいなのに対しては
DeviceIOControlを使って
後はユーザーの権限でチェックが出来ればと考えていました。
しかし、 権限のチェックには行き詰っている状態です。
もしサンプル等があれば提示していただけるとありがたいです。


結局 あんまりよくわかっていないのですが
D:AI(A;ID;FA;;;BA)(A;OICIIOID;GA;;;BA) こーいうのを解析して
特権があったらOK じゃなければ
所有者かEveryOneのSIDで書き込みと作成が許可だったらOK じゃなければ
UsersのSIDで... etc っていうようにやらなきゃいけないのか
というところもいまいち分かってないです。
(GetEffectiveRightsFromAcl と AccessCheckは駄目?)


>テンポラリーファイルなら、後の事は考えなくても良かった様な。。
なるほど、 そーいう手もあるんですね。 残ってしまうことがあるようですが。
上記はサンプルがなければ 調べるのに工数がかかってしまうから
残ってしまうリスク そのぐらいは制約としておけるかもしれません。

>いっそ(もし本当にログなら)『「ログフォルダを変更した」というログを書き込む』と
もしログであればこれはなかなかいけてるアイデアですね。

aetos 2009/04/03(金) 12:06:39
まず方針を決めましょう。

おそらく、回答者の多くは、権限チェックなんかせず、試しにファイルを作ってみるだけ
でいいじゃんと思っていると思います。
たろさんは、試しに作ってみるのは最後の手段として、それ以外の方法で判別できるなら
可能な限りそうしたいと思っていますか?
試しに作ってみると、削除できないケースが稀に発生するという欠点があります。
一方、可能な限り他の手段を試すのは、実装にもテストにも時間がかかります。
どちらの方法でも、チェックでOKでも実際の書き込みで失敗するという可能性は排除しき
れません。

aetos 2009/04/03(金) 12:13:19
あと、何点か指摘。

> DeviceIOControlで指定するCreateFileのハンドルに
> 【\\.\ドライブ名:】や、【\\.\PHYSICALDRIVEx】

これは、ドライブのセクタを直接読み書きしたりするときに使うものだと思います。
そのために必要な権限と、そのドライブにファイルを作成するために必要な権限は違いま
すから、場合によっては余分な制限がかかってしまうかもしれません。

> D:AI(A;ID;FA;;;BA)(A;OICIIOID;GA;;;BA) こーいうのを解析して
> 特権があったらOK じゃなければ

そーいうのは「特権」ではなく「アクセス権限」と呼びます。
「特権」というと別物になりますので注意してください。
権限がなくても特権があればアクセスに成功するということもあり得ます。

> (GetEffectiveRightsFromAcl と AccessCheckは駄目?)

GetEffectiveRightsFromAcl はまさに、特権を考慮しないという問題があります。
http://eternalwindows.jp/security/accesscontrol/accesscontrol14.html

aetos 2009/04/03(金) 12:14:52
連投ごめん。

ログファイルの場所をユーザに指定させない、というのはナシですか?
ユーザごとの AppData フォルダや Temp フォルダに吐き出すのが一般的だと思います
が。

たろ 2009/04/03(金) 13:02:01
>たろさんは、試しに作ってみるのは最後の手段として、それ以外の方法で判別できるな
>ら可能な限りそうしたいと思っていますか?
おっしゃるとおりです。しかし、
「フォルダ選択後のアクセス権チェンジ、容量不足、ディスクが故障したとかネットワ
ークの断線など
書き込み時エラーに関しては、無視しあくまで選択決定時に明らかである判別結果でよ
いということなのでこの辺りは考えなくてよい」
というのを制約としてです。


>すから、場合によっては余分な制限がかかってしまうかもしれません。
DeviceIOControlを用いてメディアにプロテクトがかかっていた場合に
書き込めないということの判別が出来そうだったのでこれを使おうと考えました。
その余分な制限というのは書き込める場合でも書き込めないと判断される
ケースがあるということですか?

>ログファイルの場所をユーザに指定させない、というのはナシですか?
はい、 それはナシです。(実際はログファイルではないです。)

まだあまり よくわかっていないのでうまく書きようがなかったのですが、

>権限がなくても特権があればアクセスに成功する
まさにそのことを言いたかったが為にまず特権があればOKでという意味で書いたので
す。ACEからは特権に関しては読み取れないよという意味での指摘ですか?
そのほかにも色々とルールがあるみたいで
この辺りをきちんと押さえるのは大変そうですよね。 
サンプルを見つけたいところです。。

aetos 2009/04/03(金) 14:05:05
> 書き込める場合でも書き込めないと判断されるケースがあるということですか?

はい。
例えば、CreateFile で PHYSICALDRIVEX を開くには管理者権限が必要です。

ドライブ自体が書き込み可能な種類かどうかは、チェックした時とその後で違うというこ
とは、あまりないと思いますから、実際に書き込みアクセスしてみるのではなく、種類に
よるチェックもそれなりに有効だと思います。
まぁ、メディアが入ってないとかはあるでしょうけど。

GetDriveType では書き込み可能かどうかは取得できないようです。
WMI を使えば可能かもしれません。例えばこのへん。
http://msdn.microsoft.com/en-us/library/aa394346.aspx
フロッピーの書き込み禁止タブの状態まで取得できるみたいですね。全てのドライブが対
応してるかどうかはわかりませんが。

C++ から WMI を使うのは面倒ですけどね。

> ACEからは特権に関しては読み取れないよという意味での指摘ですか?

はい。

アクセス権については、俺はいつもここを参考にしてます。
http://eternalwindows.jp/security/accesscontrol/accesscontrol00.html

ITO 2009/04/11(土) 09:45:12
 まず、ドライブが物理的・論理的に存在するかどうかを調べて、存在してなければ、
「デバイスが存在しません。」等のエラーをだしてルーチンを抜ける。
 次にデバイスの物理的な書き込みの有無に関しては実際に書込んでみなければ
分かりません。
> DeviceIOControlを用いてメディアにプロテクトがかかっていた場合に
> 書き込めないということの判別が出来そうだったのでこれを使おうと考えました。
 DeviceIOControlは、基本的にデバイスドライバーとやり取りする関数ですよね。
ということは、CD-ROM,HD,外付けUSBメモリー,SCSI等によってコマンドが違います。
もちろんアドレスも変わります。ATAPI、USBSTOR等未だコマンドがあまり公開されて
いないドライバーもあります。
結構大変です。

 セキュリティー等で書込みが制限されているかどうかの判定は何か方法があるかも
知れません。

古いスレッドには追加発言できません。