C ++ - Как установить права доступа к файлам (кросс-платформенный) - PullRequest
22 голосов
/ 27 февраля 2009

Я использую C ++ ofstream для записи файла. Я хочу, чтобы разрешения были доступны только пользователю: 700. В Unix; Я полагаю, что могу просто выдать system("chmod 700 file.txt");, но этот код мне нужен и для работы в Windows. Я могу использовать некоторые API Windows; но какой лучший кроссплатформенный способ c ++ сделать это?

Ответы [ 8 ]

29 голосов
/ 27 февраля 2009

По иронии судьбы, сегодня я столкнулся с той же самой необходимостью.

В моем случае ответ сводился к тому, какой уровень детализации разрешений мне нужен в Windows по сравнению с Linux. В моем случае, я забочусь только о правах пользователя, группы и других в Linux. В Windows для меня достаточно базового разрешения на чтение / запись всех из DOS, т. Е. Мне не нужно иметь дело с ACL в Windows.

Вообще говоря, в Windows есть две модели привилегий: базовая модель DOS и более новая модель контроля доступа. В модели DOS есть один тип привилегий: право на запись. Все файлы могут быть прочитаны, поэтому нет возможности отключить разрешение на чтение (потому что оно не существует). Также нет концепции разрешения на выполнение. Если файл может быть прочитан (ответ - да), и он является двоичным, то он может быть выполнен; в противном случае это невозможно.

Базовая модель DOS достаточна для большинства сред Windows, т. Е. Сред, в которых система используется одним пользователем в физическом месте, которое можно считать относительно безопасным. Модель контроля доступа более сложна на несколько порядков.

Модель контроля доступа использует списки контроля доступа (ACL) для предоставления привилегий. Привилегии могут быть предоставлены только процессом с необходимыми привилегиями. Эта модель не только позволяет управлять пользователями, группами и другими с разрешениями «Чтение», «Запись» и «Выполнять», но также позволяет управлять файлами по сети и между доменами Windows. (Вы также можете получить этот уровень безумия в системах Unix с PAM.)

Примечание. Модель контроля доступа доступна только для разделов NTFS, если вы используете разделы FAT, то вы SOL.

Использование ACL - большая боль в заднице. Это не тривиальное мероприятие, и вам потребуется изучить не только ACL, но и все о дескрипторах безопасности, токенах доступа и множестве других передовых концепций безопасности Windows.

К счастью для меня, для моих текущих потребностей мне не нужна настоящая безопасность, которую обеспечивает модель контроля доступа. Я могу обойтись, в основном, притворяясь, что устанавливаю разрешения в Windows, если я действительно устанавливаю разрешения в Linux.

Windows поддерживает то, что они называют «совместимой с ISO C ++» версией chmod (2). Этот API называется _chmod, и он похож на chmod (2), но более ограничен и не совместим с типом или именем (конечно). В Windows также есть устаревший chmod, поэтому вы не можете просто добавить chmod в Windows и использовать прямой chmod (2) в Linux.

Я написал следующее:

#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 голосов
/ 27 февраля 2009

Нет кроссплатформенного способа сделать это. Windows не поддерживает файловые разрешения в стиле Unix. Чтобы сделать то, что вы хотите, вам нужно будет создать список контроля доступа для этого файла, который позволит вам явно определять права доступа для пользователей и групп.

Альтернативой может быть создание файла в каталоге, параметры безопасности которого уже установлены, чтобы исключить всех, кроме пользователя.

4 голосов
/ 19 октября 2017

Кроссплатформенный пример для установки 0700 для файла с C ++ 17 и его std::filesystem.

#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::permissions, std::filesystem::perms и std::filesystem::perm_options.

3 голосов
/ 27 февраля 2009

Зов system() - странный зверь. Я был укушен реализацией NOP system () на Mac много месяцев назад. Это реализация, определяющая, что стандарт не определяет, что должна делать реализация (платформа / компилятор). К сожалению, это также единственный стандартный способ сделать что-то, выходящее за рамки вашей функции (в вашем случае - изменение разрешений).

Обновление: Предлагаемый взлом:

  • Создайте непустой файл с соответствующими разрешениями в вашей системе.
  • Используйте Boost Filesystem copy_file, чтобы скопировать этот файл в нужный вывод.

    void copy_file(const path& frompath, const path& topath): содержимое и атрибуты файла, на который ссылается frompath, копируются в файл, на который указывает topath. Эта процедура ожидает, что файл назначения отсутствует; если файл назначения присутствует, он генерирует исключение. Следовательно, это не эквивалентно системной команде cp в UNIX. Также ожидается, что переменная frompath будет ссылаться на правильный обычный файл. Рассмотрим этот пример: frompath ссылается на символическую ссылку / tmp / file1, которая, в свою очередь, ссылается на файл / tmp / file2; topath, скажем, / tmp / file3. В этой ситуации copy_file не удастся. Это еще одно отличие этого API по сравнению с командой cp.

  • Теперь перезаписать вывод фактическим содержимым.

Но это всего лишь взлом, о котором я думал задолго до полуночи. Возьми это с щепоткой соли и попробуй это:)

1 голос
/ 25 ноября 2009

Я только что нашел пару способов сделать chmod 700 легко из командной строки Windows. Я собираюсь опубликовать еще один вопрос с просьбой о помощи, чтобы придумать эквивалентную структуру дескриптора безопасности win32 для использования (если я не смогу это выяснить в ближайшие несколько часов).

Windows 2000 & XP (грязно - кажется, всегда подсказывает):

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

Windows 2003 +:

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

EDIT:

Если у вас была возможность использовать ATL, эта статья посвящена этому вопросу (у меня нет доступной Visual Studio): http://www.codeproject.com/KB/winsdk/accessctrl2.aspx

На самом деле, он говорит, что пример кода также включает в себя пример кода не-ATL - он должен иметь что-то, что работает для вас (и меня!)

Важно помнить, что для владельца r / w / x нужно получить только на win32, вам просто нужно стереть все дескрипторы безопасности из файла и добавить один для себя с полным контролем.

1 голос
/ 27 февраля 2009

Нет стандартного способа сделать это в C ++, но для этого специального требования вам, вероятно, следует просто написать пользовательскую оболочку с #ifdef _WIN32. Qt имеет оболочку прав доступа в своем классе QFile , но это, конечно, будет зависеть от Qt ...

1 голос
/ 27 февраля 2009

Не знаю, сработает ли это, но вы можете использовать исполняемый файл chmod.exe, поставляемый с Cygwin.

0 голосов
/ 27 февраля 2009

Вы не можете сделать это кроссплатформенным способом. В Linux вы должны использовать функцию chmod(2) вместо использования system(2) для создания новой оболочки. В Windows вам придется использовать различные функции авторизации , чтобы создать ACL (список контроля доступа) с соответствующими разрешениями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...