2009-02-26 286 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