2016-05-31 19:20:38 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#define NOMINMAX
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2016-05-31 19:20:38 +00:00
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
#include <boost/optional.hpp>
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
#include <osquery/status.h>
|
|
|
|
|
2016-05-31 19:20:38 +00:00
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
|
|
|
using mode_t = int;
|
|
|
|
using ssize_t = SSIZE_T;
|
|
|
|
using PlatformHandle = HANDLE;
|
|
|
|
using PlatformTimeType = FILETIME;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Windows does not define these, X_OK on Windows just ensures that the
|
|
|
|
* file is readable.
|
|
|
|
*/
|
|
|
|
#define F_OK 0
|
|
|
|
#define R_OK 4
|
|
|
|
#define W_OK 2
|
|
|
|
#define X_OK R_OK
|
|
|
|
|
2016-07-01 21:56:07 +00:00
|
|
|
// Windows does not define these constants, and they are neater
|
|
|
|
// than using raw octal for platformChmod, etc.
|
|
|
|
#define S_IRUSR 0400
|
|
|
|
#define S_IWUSR 0200
|
|
|
|
#define S_IXUSR 0100
|
2016-07-11 16:45:57 +00:00
|
|
|
#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
|
2016-07-01 21:56:07 +00:00
|
|
|
|
|
|
|
#define S_IRGRP (S_IRUSR >> 3)
|
|
|
|
#define S_IWGRP (S_IWUSR >> 3)
|
|
|
|
#define S_IXGRP (S_IXUSR >> 3)
|
|
|
|
#define S_IRWXG (S_IRWXU >> 3)
|
|
|
|
|
|
|
|
#define S_IROTH (S_IRGRP >> 3)
|
|
|
|
#define S_IWOTH (S_IWGRP >> 3)
|
|
|
|
#define S_IXOTH (S_IXGRP >> 3)
|
|
|
|
#define S_IRWXO (S_IRWXG >> 3)
|
|
|
|
|
2016-05-31 19:20:38 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
using PlatformHandle = int;
|
|
|
|
using PlatformTimeType = struct timeval;
|
|
|
|
#endif
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
typedef struct { PlatformTimeType times[2]; } PlatformTime;
|
2016-05-31 19:20:38 +00:00
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Constant for an invalid handle.
|
2016-05-31 19:20:38 +00:00
|
|
|
const PlatformHandle kInvalidHandle = (PlatformHandle)-1;
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief File access modes for PlatformFile.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
|
|
|
* A file can be opened for many access modes with a variety of different
|
|
|
|
* options on Windows and POSIX. To provide multi-platform support, we need to
|
|
|
|
* provide an abstraction that can cover the supported platforms.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define PF_READ 0x0001
|
|
|
|
#define PF_WRITE 0x0002
|
|
|
|
|
|
|
|
#define PF_OPTIONS_MASK 0x001c
|
|
|
|
#define PF_GET_OPTIONS(x) ((x & PF_OPTIONS_MASK) >> 2)
|
|
|
|
#define PF_CREATE_NEW (0 << 2)
|
|
|
|
#define PF_CREATE_ALWAYS (1 << 2)
|
|
|
|
#define PF_OPEN_EXISTING (2 << 2)
|
|
|
|
#define PF_TRUNCATE (3 << 2)
|
|
|
|
|
|
|
|
#define PF_NONBLOCK 0x0020
|
2016-07-11 16:45:57 +00:00
|
|
|
#define PF_APPEND 0x0040
|
2016-05-31 19:20:38 +00:00
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Modes for seeking through a file.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
|
|
|
* Provides a platform agnostic enumeration for file seek operations. These
|
|
|
|
* are translated to the appropriate flags for the underlying platform.
|
|
|
|
*/
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
enum SeekMode { PF_SEEK_BEGIN = 0, PF_SEEK_CURRENT, PF_SEEK_END };
|
2016-05-31 19:20:38 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Stores information about the last Windows async request
|
|
|
|
* @note Currently, we have rudimentary support for non-blocking operations
|
|
|
|
* on Windows. The implementation attempts to emulate POSIX non-blocking
|
|
|
|
* IO semantics using the Windows asynchronous API. As such, there are
|
|
|
|
* currently limitations. For example, opening a non-blocking file with
|
|
|
|
* read and write privileges may produce some problems. If a write
|
|
|
|
* operation does not immediately succeed, we cancel IO instead of
|
|
|
|
* waiting on it. As a result, on-going async read operations will get
|
2016-07-11 16:45:57 +00:00
|
|
|
* canceled and data might get lost.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
|
|
|
* Windows-only class that deals with simulating POSIX asynchronous IO semantics
|
|
|
|
* using Windows API calls
|
|
|
|
*/
|
|
|
|
struct AsyncEvent {
|
2016-07-11 16:45:57 +00:00
|
|
|
AsyncEvent();
|
|
|
|
~AsyncEvent();
|
|
|
|
|
|
|
|
OVERLAPPED overlapped_{0};
|
|
|
|
std::unique_ptr<char[]> buffer_{nullptr};
|
|
|
|
bool is_active_{false};
|
2016-05-31 19:20:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Platform-agnostic file object.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
2016-07-11 16:45:57 +00:00
|
|
|
* PlatformFile is a multi-platform class that offers input/output capabilities
|
|
|
|
* for files.
|
2016-05-31 19:20:38 +00:00
|
|
|
*/
|
|
|
|
class PlatformFile {
|
|
|
|
public:
|
|
|
|
explicit PlatformFile(const std::string& path, int mode, int perms = -1);
|
|
|
|
explicit PlatformFile(PlatformHandle handle) : handle_(handle) {}
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
PlatformFile(PlatformFile&& src) noexcept {
|
2016-05-31 19:20:38 +00:00
|
|
|
handle_ = kInvalidHandle;
|
|
|
|
std::swap(handle_, src.handle_);
|
|
|
|
}
|
|
|
|
|
|
|
|
~PlatformFile();
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Checks to see if the file object is "special file".
|
2016-06-07 21:08:50 +00:00
|
|
|
bool isSpecialFile() const;
|
2016-05-31 19:20:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Checks to see if there are any pending IO operations.
|
|
|
|
*
|
|
|
|
* This is mostly used after a read()/write() error in non-blocking mode to
|
|
|
|
* determine the intention of the error. If read()/write() returns an error
|
|
|
|
* and hasPendingIo() is true, this indicates that the read()/write()
|
|
|
|
* operation didn't complete on time.
|
|
|
|
*/
|
2016-07-11 16:45:57 +00:00
|
|
|
bool hasPendingIo() const { return has_pending_io_; }
|
2016-05-31 19:20:38 +00:00
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Checks to see if the handle backing the PlatformFile object is valid.
|
2016-05-31 19:20:38 +00:00
|
|
|
bool isValid() const { return (handle_ != kInvalidHandle); }
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Returns the platform specific handle.
|
2016-05-31 19:20:38 +00:00
|
|
|
PlatformHandle nativeHandle() const { return handle_; }
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Returns success if owner of the file is root.
|
2016-05-31 19:20:38 +00:00
|
|
|
* @note At the moment, we only determine that the owner of the current file
|
2016-07-11 16:45:57 +00:00
|
|
|
* is a member of the Administrators group. We do not count files owned
|
|
|
|
* by TrustedInstaller as owned by root.
|
2016-05-31 19:20:38 +00:00
|
|
|
*/
|
|
|
|
Status isOwnerRoot() const;
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Returns success if the owner of the file is the current user.
|
2016-05-31 19:20:38 +00:00
|
|
|
Status isOwnerCurrentUser() const;
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Determines whether the file has the executable bit set.
|
2016-05-31 19:20:38 +00:00
|
|
|
Status isExecutable() const;
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Determines how immutable the file is to external modifications.
|
2016-06-07 21:08:50 +00:00
|
|
|
* @note Currently, this is only implemented on Windows. The Windows version
|
|
|
|
* of this function ensures that writes are explicitly denied for the
|
|
|
|
* file and the file's parent directory.
|
|
|
|
*/
|
|
|
|
Status isNonWritable() const;
|
|
|
|
|
2016-05-31 19:20:38 +00:00
|
|
|
bool getFileTimes(PlatformTime& times);
|
2016-07-11 16:45:57 +00:00
|
|
|
|
2016-05-31 19:20:38 +00:00
|
|
|
bool setFileTimes(const PlatformTime& times);
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
ssize_t read(void* buf, size_t nbyte);
|
|
|
|
|
|
|
|
ssize_t write(const void* buf, size_t nbyte);
|
|
|
|
|
2016-05-31 19:20:38 +00:00
|
|
|
off_t seek(off_t offset, SeekMode mode);
|
|
|
|
|
|
|
|
size_t size() const;
|
|
|
|
|
|
|
|
private:
|
2016-07-11 16:45:57 +00:00
|
|
|
PlatformHandle handle_{kInvalidHandle};
|
2016-05-31 19:20:38 +00:00
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
bool is_nonblock_{false};
|
|
|
|
|
|
|
|
bool has_pending_io_{false};
|
2016-05-31 19:20:38 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2016-07-11 16:45:57 +00:00
|
|
|
int cursor_{0};
|
2016-05-31 19:20:38 +00:00
|
|
|
|
|
|
|
AsyncEvent last_read_;
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
ssize_t getOverlappedResultForRead(void* buf, size_t requested_size);
|
2016-05-31 19:20:38 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Returns the current user's home directory.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
|
|
|
* This uses multiple methods to find the current user's home directory. It
|
|
|
|
* attempts to use environment variables first and on failure, tries to obtain
|
|
|
|
* the path using platform specific functions. Returns a boost::none on the
|
|
|
|
* failure of both methods.
|
|
|
|
*/
|
|
|
|
boost::optional<std::string> getHomeDirectory();
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Multi-platform implementation of chmod.
|
2016-05-31 19:20:38 +00:00
|
|
|
* @note There are issues with the ACL being ordered "incorrectly". This
|
|
|
|
* incorrect ordering does help with implementing the proper
|
|
|
|
* behaviors
|
2016-07-11 16:45:57 +00:00
|
|
|
*
|
2016-05-31 19:20:38 +00:00
|
|
|
* This function approximates the functionality of the POSIX chmod function on
|
|
|
|
* Windows. While there is the _chmod function on Windows, it does not support
|
|
|
|
* the user, group, world permissions model. The Windows version of this
|
|
|
|
* function will approximate it by using GetNamedSecurityInfoA to obtain the
|
|
|
|
* file's owner and group. World is represented by the Everyone group on
|
|
|
|
* Windows. Allowed permissions are represented by an access allowed access
|
|
|
|
* control entry and unset permissions are represented by an explicit access
|
|
|
|
* denied access control entry. However, the Windows preference for ACL ordering
|
|
|
|
* creates some problems. For instance, if a user wishes to protect a file by
|
|
|
|
* denying world access to a file, the normal standard for ACL ordering will end
|
|
|
|
* up denying everyone, including the user, to the file (because of the deny
|
|
|
|
* Everyone access control entry that is first in the ACL). To counter this, we
|
|
|
|
* have to be more creative with the ACL order which presents some problems for
|
|
|
|
* when attempting to modify permissions via File Explorer (complains of a
|
2016-07-11 16:45:57 +00:00
|
|
|
* mis-ordered ACL and offers to rectify the problem).
|
2016-05-31 19:20:38 +00:00
|
|
|
*/
|
|
|
|
bool platformChmod(const std::string& path, mode_t perms);
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Multi-platform implementation of glob.
|
2016-05-31 19:20:38 +00:00
|
|
|
* @note glob support is not 100% congruent with Linux glob. There are slight
|
2016-07-11 16:45:57 +00:00
|
|
|
* differences in how GLOB_TILDE and GLOB_BRACE are implemented.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
|
|
|
* This function approximates the functionality of the POSIX glob function on
|
|
|
|
* Windows. It has naive support of GLOB_TILDE (doesn't support ~user syntax),
|
|
|
|
* GLOB_MARK, and GLOB_BRACE (custom translation of glob expressions to regex).
|
|
|
|
*/
|
|
|
|
std::vector<std::string> platformGlob(const std::string& find_path);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Checks to see if the current user has the permissions to perform a
|
2016-07-11 16:45:57 +00:00
|
|
|
* specified operation on a file.
|
2016-05-31 19:20:38 +00:00
|
|
|
*
|
|
|
|
* This abstracts the POSIX access function across Windows and POSIX. On
|
|
|
|
* Windows, this calls the equivalent _access function.
|
|
|
|
*/
|
|
|
|
int platformAccess(const std::string& path, mode_t mode);
|
|
|
|
|
|
|
|
/**
|
2016-07-11 16:45:57 +00:00
|
|
|
* @brief Checks to see if the provided directory is a temporary folder.
|
2016-05-31 19:20:38 +00:00
|
|
|
* @note This just compares the temporary directory path against the given path
|
2016-07-11 16:45:57 +00:00
|
|
|
* on Windows.
|
2016-05-31 19:20:38 +00:00
|
|
|
*/
|
|
|
|
Status platformIsTmpDir(const fs::path& dir);
|
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Determines the accessibility and existence of the file path.
|
2016-05-31 19:20:38 +00:00
|
|
|
Status platformIsFileAccessible(const fs::path& path);
|
2016-07-01 21:56:07 +00:00
|
|
|
|
2016-07-11 16:45:57 +00:00
|
|
|
/// Determine if the FILE object points to a tty (console, serial port, etc).
|
|
|
|
bool platformIsatty(FILE* f);
|
2016-05-31 19:20:38 +00:00
|
|
|
}
|