2009-02-26 25 views
19

私はファイルを書き出すためにC++ ofstreamを使用しています。私はアクセス権をユーザーがアクセスできるように設定したい:700. Unixでは、私はちょうどsystem("chmod 700 file.txt");を発行することができますが、私はこのコードもWindows上で動作する必要があります。私はいくつかのWindows APIを使うことができます。これを行うには最高のC++クロスプラットフォームの方法は何ですか?C++ - ファイル許可を設定する方法(クロスプラットフォーム)

+0

恐ろしい!安全でない! 'system(" chmod ")'のようなクレイジーなハックを使わずに、ファイルを作成してからアクセス権を修正してください。代わりに、制限のあるアクセス許可で作成し、レースフリーのAPIを使用するようにしてください。 'umask'(スレッドセーフではない)または' open + fchmod + fdopen + std :: fstream'を使用してください。 –

+0

機密データをファイルに書き込む前にchmodが使用されている限り、chmodの使用には何も問題ありません。あなたはfchmod()がchmodと非常に似ている、あなたの "答え"に気付いていますよね? – samoz

答えて

23

皮肉なことに、私はちょうどこのまさに同じ必要性に今すぐ遭遇しました。

私のケースでは、答えは、Linuxと比較して、Windowsで必要な権限レベルのレベルまで下がっています。私の場合、私はLinuxのユーザー、グループ、およびその他のアクセス許可のみに注意します。 Windowsでは、DOSからの基本的な読み取り/書き込みすべての権限は十分です。つまり、Windows上でACLを処理する必要はありません。

一般に、Windowsには基本的なDOSモデルと新しいアクセス制御モデルの2つの特権モデルがあります。 DOSモデルでは、1つのタイプの特権、書き込み特権があります。すべてのファイルを読み取ることができるため、読み取り権限を無効にする方法はありません(存在しないため)。実行権限の概念もありません。ファイルを読み取ることができれば(答えはイエス)、バイナリであれば実行できます。それ以外の場合はできません。

ほとんどのWindows環境、つまり比較的安全であると考えることができる物理的な場所で単一のユーザーがシステムを使用する環境では、基本的なDOSモデルで十分です。アクセス制御モデルは、数桁程度複雑です。

アクセス制御モデルでは、アクセス制御リスト(ACL)を使用して特権を付与します。特権は、必要な特権を持つプロセスによってのみ付与されます。このモデルは、読み取り、書き込み、および実行の権限を持つユーザー、グループ、その他のコントロールを許可するだけでなく、ネットワーク上およびWindowsドメイン間のファイルの制御も可能です。

注意:アクセスコントロールモデルは、あなたがSOLであるFATパーティションを使用している場合にのみNTFSパーティションで利用できます。

ACLを使用することはお尻の大きな痛みです。これは簡単な作業ではなく、ACLだけでなく、セキュリティ記述子、アクセストークン、その他の高度なWindowsセキュリティの概念についても学ぶ必要があります。

幸い私の現在のニーズのために、アクセスコントロールモデルが提供する真のセキュリティは必要ありません。私は、基本的にLinux上でパーミッションを設定している限り、Windows上でパーミッションを設定しようとしています。

Windowsでは、「ISO C++準拠」バージョンのchmod(2)をサポートしています。このAPIは_chmodと呼ばれ、chmod(2)と似ていますが、より限定されており、型や名前には互換性がありません(もちろん)。 Windowsでは廃止予定のchmodもありますので、単にWindowsにchmodを追加するだけではなく、Linux上で直接chmod(2)を使用することはできません。

私は次のように書いた:

#include <sys/stat.h> 
#include <sys/types.h> 

#ifdef _WIN32 
# include <io.h> 

typedef int mode_t; 

/// @Note If STRICT_UGO_PERMISSIONS is not defined, then setting Read for any 
///  of User, Group, or Other will set Read for User and setting Write 
///  will set Write for User. Otherwise, Read and Write for Group and 
///  Other are ignored. 
/// 
/// @Note For the POSIX modes that do not have a Windows equivalent, the modes 
///  defined here use the POSIX values left shifted 16 bits. 

static const mode_t S_ISUID  = 0x08000000;   ///< does nothing 
static const mode_t S_ISGID  = 0x04000000;   ///< does nothing 
static const mode_t S_ISVTX  = 0x02000000;   ///< does nothing 
static const mode_t S_IRUSR  = mode_t(_S_IREAD);  ///< read by user 
static const mode_t S_IWUSR  = mode_t(_S_IWRITE); ///< write by user 
static const mode_t S_IXUSR  = 0x00400000;   ///< does nothing 
# ifndef STRICT_UGO_PERMISSIONS 
static const mode_t S_IRGRP  = mode_t(_S_IREAD);  ///< read by *USER* 
static const mode_t S_IWGRP  = mode_t(_S_IWRITE); ///< write by *USER* 
static const mode_t S_IXGRP  = 0x00080000;   ///< does nothing 
static const mode_t S_IROTH  = mode_t(_S_IREAD);  ///< read by *USER* 
static const mode_t S_IWOTH  = mode_t(_S_IWRITE); ///< write by *USER* 
static const mode_t S_IXOTH  = 0x00010000;   ///< does nothing 
# else 
static const mode_t S_IRGRP  = 0x00200000;   ///< does nothing 
static const mode_t S_IWGRP  = 0x00100000;   ///< does nothing 
static const mode_t S_IXGRP  = 0x00080000;   ///< does nothing 
static const mode_t S_IROTH  = 0x00040000;   ///< does nothing 
static const mode_t S_IWOTH  = 0x00020000;   ///< does nothing 
static const mode_t S_IXOTH  = 0x00010000;   ///< does nothing 
# endif 
static const mode_t MS_MODE_MASK = 0x0000ffff;   ///< low word 

static inline int my_chmod(const char * path, mode_t mode) 
{ 
    int result = _chmod(path, (mode & MS_MODE_MASK)); 

    if (result != 0) 
    { 
     result = errno; 
    } 

    return (result); 
} 
#else 
static inline int my_chmod(const char * path, mode_t mode) 
{ 
    int result = chmod(path, mode); 

    if (result != 0) 
    { 
     result = errno; 
    } 

    return (result); 
} 
#endif 

私の解決策が唯一のDOSタイプのセキュリティを提供することを覚えておくことが重要です。これはセキュリティなしとも呼ばれますが、ほとんどのアプリがWindows上であなたに与えるセキュリティの量です。

STRICT_UGO_PERMISSIONSを定義していない場合、私の解決策では、グループやその他の権限(またはその問題に関して削除する権限)を与えても、実際に所有者が変更されています。これをやりたくないのですが、それでもWindowsの全ACL権限が必要ない場合は、STRICT_UGO_PERMISSIONSを定義してください。

8

これを実行するためのクロスプラットフォームの方法はありません。 WindowsはUnix形式のファイルアクセス許可をサポートしていません。必要な作業を行うには、そのファイルのアクセス制御リストを作成する必要があります。これにより、ユーザーとグループのアクセス許可を明示的に定義できます。

セキュリティ設定がすでに設定されているディレクトリにファイルを作成し、そのユーザー以外のすべてのユーザーを除外することもできます。

+0

その答えは、人々が実際に考えるべきものです。アプリのアクセス権を本当に必要としているのですか?多くの場合、多くの場合、管理者やユーザーは適切なアクセス権を制御することができるため、多くの場合、それは事実ではないし、物事を壊すことさえあります。特に。 Windowsでは、デフォルトでは他のユーザーがユーザーのホームディレクトリにアクセスすることはできないため、ファイルを手動で「非公開」にする必要はほとんどありません。 Linuxアプリケーションのchmod + umask処理の多くは、ACLや適切な継承などがないために残っています。可能な限り避けてください。 –

1

Cygwinに付属のchmod.exe実行ファイルを使用して調べることができます。

+0

+1というのは興味深い考えだからです。 Cygwinの下のchmodは私がこれまで試したことがあるたびに正しいことをしていることは分かっています。 – rmeador

+0

何ですか?それはNTFSのACLを変更する? – aib

1

C++でこれを行う標準的な方法はありませんが、この特別な要件のためにおそらく#ifdef _WIN32を使用してカスタムラッパーを作成するだけです。 QtはQFileクラスのパーミッションラッパーを持っていますが、これはもちろんQtに依存します...

+0

あなたが提供したリンクに関する警告は、これがWindows上で期待通りに機能しない可能性があることを意味します。 – Ferruccio

0

クロスプラットフォームの方法ではできません。 Linuxでは、system(2)を使用して新しいシェルを作成する代わりに、関数chmod(2)を使用する必要があります。 Windowsでは、様々なauthorization functionsを使用して、適切な権限を持つACL(アクセス制御リスト)を作成する必要があります。

3

system()コールは変な獣です。私は多くの月前のMacでNOPシステム()の実装に噛まれています。実装定義(プラットフォーム/コンパイラ)が何をすべきかを定義していないことを意味する実装定義です。残念ながら、これはあなたの関数の範囲外のことを行う唯一の標準的な方法です(あなたの場合は権限を変更する)。

更新:提案ハック:

  • お使いのシステムに適切な権限を持つ非空のファイルを作成します。
  • ブーストファイルシステムのcopy_fileを使用して、このファイルを目的の出力にコピーします。

    void copy_file(const path& frompath, const path& topath):frompathが参照するファイルの内容と属性は、topathが参照するファイルにコピーされます。このルーチンは、宛先ファイルが存在しないことを前提としています。宛先ファイルが存在する場合、例外がスローされます。したがって、これはUNIXのシステム指定のcpコマンドと等価ではありません。また、frompath変数が適切な正規ファイルを参照することも期待されます。次の例を考えてみましょう:frompathは/ tmp/file1というシンボリックリンクを参照し、/ tmp/file2というファイルを参照します。 topathは、例えば、/ tmp/file3です。この場合、copy_fileは失敗します。これは、このAPIのスポーツがcpコマンドと比較して、さらに別の違いです。

  • ここで、出力を実際の内容で上書きします。

しかし、これは私が真夜中の後に長い考えるだけハックです。塩のピンチでそれを取って、これを試してください:)

1

私は、Windowsコマンドラインからchmod 700の簡単な方法をいくつか見つけました。私は別の質問を投稿して、使用する同等のwin32セキュリティ記述子構造を思いつくための助けを頼んでいます(もし私が数時間後にそれを理解できなければ)。

のWindows 2000 & XP(常に求められているようだmessy-):

echo Y|cacls *onlyme.txt* /g %username%:F 

のWindows 2003+:

icacls *onlyme.txt* /inheritance:r /grant %username%:r 

EDIT:

あなたが能力を持っていた場合ATLを使用すると、この記事で説明しています(私はVisual Studioを利用できません): ​​

実際には、サンプルコードは、それはあなたのために働く何か持っている必要がありますよく、非ATLのサンプルコードが含ま言う(私を!)

覚えておくべき重要なことは、R/W得ることです/ xはwin32のみの所有者であるため、ファイルからすべてのセキュリティ記述子を抹消し、完全に制御できるように自分で追加する必要があります。

2

クロスプラットフォームの例では、C++ 17およびそのstd::filesystemのファイルに対して0700を設定しています。

#include <exception> 
//#include <filesystem> 
#include <experimental/filesystem> // Use this for most compilers as of yet. 

//namespace fs = std::filesystem; 
namespace fs = std::experimental::filesystem; // Use this for most compilers as of yet. 

int main() 
{ 
    fs::path myFile = "path/to/file.ext"; 
    try { 
     fs::permissions(myFile, fs::perms::owner_all); // Uses fs::perm_options::replace. 
    } 
    catch (std::exception& e) { 
     // Handle exception or use another overload of fs::permissions() 
     // with std::error_code. 
    }   
} 

std::filesystem::permissionsstd::filesystem::permsstd::filesystem::perm_optionsを参照してください。

関連する問題