2009-02-26 113 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`。 – 2013-09-09 22:57:35

+0

使用chmod沒有任何問題,只要在將敏感數據寫入文件之前使用chmod即可。你在你的「答案」中意識到fchmod()與chmod非常相似,對吧? – samoz 2014-07-01 14:53:01

回答

23

具有諷刺意味的是,我今天早些時候剛剛遇到了這種非常相同的需求。

就我而言,答案取決於Windows和Linux所需的權限粒度級別。就我而言,我只關心Linux上的用戶,組和其他權限。在Windows上,從DOS剩餘的基本讀/寫權限對我來說足夠好,即我不需要在Windows上處理ACL。

一般來說,Windows有兩個特權模型:基本的DOS模型和較新的訪問控制模型。在DOS模式下,有一種特權:寫入特權。所有文件都可以讀取,因此無法關閉讀取權限(因爲它不存在)。也沒有執行權限的概念。如果一個文件可以被讀取(答案是肯定的)並且是二進制的,那麼它可以被執行;否則它不能。

基本的DOS模型對於大多數Windows環境(即系統被可以被認爲相對安全的物理位置中的單個用戶使用的環境)是足夠的。訪問控制模型更復雜幾個數量級。

訪問控制模型使用訪問控制列表(ACL)授予權限。特權只能由具有必要特權的進程授予。該模型不僅可以控制具有讀取,寫入和執行權限的用戶,組和其他,而且還允許通過網絡和Windows域之間的文件控制。 (你也可以在使用PAM的Unix系統上得到這種程度的精神錯亂。)

注意:如果你使用的是FAT分區,你是SOL,訪問控制模型只適用於NTFS分區。

使用ACL是一個很大的麻煩。這不是一項簡單的任務,它需要您學習不僅僅是ACL,還需要了解所有關於安全描述符,訪問令牌和大量其他高級Windows安全概念的知識。

對我來說幸運的是,對於我目前的需求,我並不需要訪問控制模型提供的真正安全性。我可以基本上假裝在Windows上設置權限,只要我真的在Linux上設置權限即可。

Windows支持他們稱之爲「ISO C++一致性」版本的chmod(2)。這個API被稱爲_chmod,它與chmod(2)類似,但是更受限制,而不是類型或名稱兼容(當然)。 Windows也有一個不推薦的chmod,所以你不能簡單地將chmod添加到Windows,並在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,適當的繼承等等。儘量避免這種情況。 – 2017-12-14 11:29:17

1

不知道它是否可行,但您可以使用Cygwin附帶的chmod.exe可執行文件進行研究。

+0

+1,因爲這是一個有趣的想法。我知道cygwin下的chmod每次嘗試都會做正確的事情。 – rmeador 2009-02-26 21:32:16

1

在C++中沒有這樣做的標準方法,但對於這個特殊的需求,你應該用#ifdef _WIN32編寫一個自定義的包裝器。 Qt有一個權限包裝在它的QFile類,但這當然意味着取決於Qt ...

0

你不能以跨平臺的方式做到這一點。在Linux中,您應該使用函數chmod(2)而不是使用system(2)來產生一個新的shell。在Windows上,您必須使用各種authorization functions來創建具有適當權限的ACL(訪問控制列表)。

3

system()電話是一個奇怪的野獸。我在很多個月前的Mac上被NOP系統()實現了。它的實現定義意味着標準沒有定義實現(平臺/編譯器)應該做什麼。不幸的是,這也是在你的函數範圍之外做一些事情的唯一標準方法(在你的情況下 - 更改權限)。

更新:擬議黑客:

  • 創建您的系統上適當權限的非空文件。
  • 使用Boost Filesystem的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命令相比的差異。

  • 現在,用實際內容覆蓋輸出。

但是,這只是我在午夜之後很久纔想到的一種破解。拿一小撮鹽來試試吧:)

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 

編輯:

如果你有能力,使用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