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(Lc:\\test.txt, CFile::modeCreate | CFile::modeWrite);
fi.Close();
ファイルの作成に失敗するのだから それを前もって知りたい
チェックしたその瞬間にはアクセス許可が[あって/なくて]
その結果に基づき、目的のファイルを作成や読み書きしようとした
まさにその瞬間にはアクセス許可が[取り消されて/追加されて]
いる、というのは現代マルチタスク・マルチユーザOSではごく普通の話なので
「事前チェックを行うこと自体が原理的に無駄」
なわけだ。俺なら事前チェックはしない。考えるだけ無駄だと思う。
そうですね、 俺もそう思います。
ですが仕様ですので、
どうにかならないものかと悩んでいる状態です。
セキュリティディスクリプタを直に読んでいくというのも
すんごく難しそうな気がするのですが、
サンプルとかすら見つけられないでいます。
とりあえず、
作業フォルダを設定する時にファイル作成や、 書き込みが出来ないフォルダ
であれば[書き込みが出来ないフォルダ]であることを知らせることができ、
もしこの設定後に フォルダのアクセス権がなくなるようなことがあった場合
そうそうあることではないと思いますし、
その時は書き込み時にエラーとするということになるかと思います。
フロッピーディスクや USB ディスクや SD メモリディスクな場合、
ユーザーの権限として書き込みができるかどうかをチェックしても結局無駄で
最終的にプロテクトノッチが禁止になっているかどうかは
実際に書き込んでみないとわからないですよ。
> ダミーでファイル作成を行いそのエラーで判断
しかない、と思うわけだが。
原理的に無駄な仕様ならば採用しなけりゃいいわけで
仕様ですから しょうがないではなくて
その仕様、意味ないですよ、変えませんか?
とその種の権限を持つ人に働きかける方向に動く気は無いですか。
そうですか。
>実際に書き込んでみないとわからないですよ。
やっぱりそうなんですね。
であれば、 DeviceIOControlで指定するCreateFileのハンドルに
【\\.\ドライブ名:】や、【\\.\PHYSICALDRIVEx】
を指定する時のように実際にファイルやフォルダ等後に残るものを作ることなく
フォルダにファイルが作成できるかどうかを判断する方法を
ご存じないでしょうか?
>とその種の権限を持つ人に働きかける方向に動く気は無いですか。
いえ、最初に仕様を決める段階ではあまり意味がないのでやめませんか。
という方向で話はしましたよ、
ですが、 書き込みが出来ないものは選択できないようにしてほしい
とのことだったので やむなしです。
(ログフォルダをフォルダ選択ツリーなどを使って指定するときのように
選択したフォルダにプログラムが自動でファイルを作成、書き込みしていくので
書き込めないフォルダを指定してもしょうがないから選択決定時に
そのフォルダが書き込み禁止であるならそのことを知らせてもらえると
使いやすいし、 分かりやすいとのこと)
後を残したくないなら実際に書いてみて、すぐに消せばいい
フォルダのプロパティの属性だとか管理者権限とか確認しても
実際にはそれ通りに動かないこともあるし
実際に書き込む以上に正しい情報は得られる方法はないでしょう
すばやい回答ありがとうございます。
>後を残したくないなら実際に書いてみて、すぐに消せばいい
出来るだけこれをやりたくないと思って色々調べていたんですが
やっぱりこれしかないってことなんですよね?
(万が一、強制終了した時とかにごみファイルが残ってしまう可能性がある為)
技術的にこれしか方法がないということであれば
了承も取れるであろうし、それまでの話なんですが
それが分からず アクセス権やら、プロテクトチェックだの難しい
情報に振り回されて行き詰っていました。
> (万が一、強制終了した時とかにごみファイルが残ってしまう可能性がある為)
Write Onlyとかでも一緒ですね。
ケーブル抜けのほか、ダミーファイルも本物と同等のサイズで書かないと、
「本物はディスク容量不足で書き込みに失敗する」とかもあるでしょうし、
大物の場合、同じサイズで書くのも無駄でしょうし…。
結局、「選んだ結果、書き込みに失敗することがあります」は消せないので、
ファイルが残る可能性があるくらいなら、実際に書き込んでみるのは
止めてしまうのも手だと思います。
どうせ完全でないと分かっている上でのガードならば、
権限で明らかに書き込みできないものだけ判断するとか
「明らかにかけないと分かっているもの」だけ検出する。
--
ログフォルダ設定時に書き込みの可否が気になるというのも分からなくはないです。
いっそ(もし本当にログなら)『「ログフォルダを変更した」というログを書き込む』と
か。
「本物のデータを書く」なら消さずに済みますから。
# でも明らかに「テストラン」を考えた方がいい気がしますが。
テンポラリーファイルなら、後の事は考えなくても良かった様な。。
CreateFile を FILE_FLAG_DELETE_ON_CLOSE 付きで使うとか。
絶対とは言えませんが、いくらかは確実&楽になるかも。
あとで書けなくなったときにエラーメッセージで済ませられるくらいなら、
今、テンポラリファイルが削除できなかった場合だってエラーメッセージで
済ませてしまっていい、ということはないかしら?
書き込み検査用に作成したファイルが削除できませんでした。
お手数ですが手動で削除してください。
ファイル名:xxxx
実際には滅多にお目にかかるエラーではないと思いますけど。
#ライフサイクル終えるまで誰も遭遇しないかも。
>どうせ完全でないと分かっている上でのガードならば、
>権限で明らかに書き込みできないものだけ判断するとか
>「明らかにかけないと分かっているもの」だけ検出する。
そうですね。 完全でないと分かっている上でのガードとして
メディアのプロテクトとか読み取り専用のCDみたいなのに対しては
DeviceIOControlを使って
後はユーザーの権限でチェックが出来ればと考えていました。
しかし、 権限のチェックには行き詰っている状態です。
もしサンプル等があれば提示していただけるとありがたいです。
結局 あんまりよくわかっていないのですが
D:AI(A;ID;FA;;;BA)(A;OICIIOID;GA;;;BA) こーいうのを解析して
特権があったらOK じゃなければ
所有者かEveryOneのSIDで書き込みと作成が許可だったらOK じゃなければ
UsersのSIDで... etc っていうようにやらなきゃいけないのか
というところもいまいち分かってないです。
(GetEffectiveRightsFromAcl と AccessCheckは駄目?)
>テンポラリーファイルなら、後の事は考えなくても良かった様な。。
なるほど、 そーいう手もあるんですね。 残ってしまうことがあるようですが。
上記はサンプルがなければ 調べるのに工数がかかってしまうから
残ってしまうリスク そのぐらいは制約としておけるかもしれません。
>いっそ(もし本当にログなら)『「ログフォルダを変更した」というログを書き込む』と
もしログであればこれはなかなかいけてるアイデアですね。
まず方針を決めましょう。
おそらく、回答者の多くは、権限チェックなんかせず、試しにファイルを作ってみるだけ
でいいじゃんと思っていると思います。
たろさんは、試しに作ってみるのは最後の手段として、それ以外の方法で判別できるなら
可能な限りそうしたいと思っていますか?
試しに作ってみると、削除できないケースが稀に発生するという欠点があります。
一方、可能な限り他の手段を試すのは、実装にもテストにも時間がかかります。
どちらの方法でも、チェックでOKでも実際の書き込みで失敗するという可能性は排除しき
れません。
あと、何点か指摘。
> DeviceIOControlで指定するCreateFileのハンドルに
> 【\\.\ドライブ名:】や、【\\.\PHYSICALDRIVEx】
これは、ドライブのセクタを直接読み書きしたりするときに使うものだと思います。
そのために必要な権限と、そのドライブにファイルを作成するために必要な権限は違いま
すから、場合によっては余分な制限がかかってしまうかもしれません。
> D:AI(A;ID;FA;;;BA)(A;OICIIOID;GA;;;BA) こーいうのを解析して
> 特権があったらOK じゃなければ
そーいうのは「特権」ではなく「アクセス権限」と呼びます。
「特権」というと別物になりますので注意してください。
権限がなくても特権があればアクセスに成功するということもあり得ます。
> (GetEffectiveRightsFromAcl と AccessCheckは駄目?)
GetEffectiveRightsFromAcl はまさに、特権を考慮しないという問題があります。
http://eternalwindows.jp/security/accesscontrol/accesscontrol14.html
連投ごめん。
ログファイルの場所をユーザに指定させない、というのはナシですか?
ユーザごとの AppData フォルダや Temp フォルダに吐き出すのが一般的だと思います
が。