mirror of https://github.com/trapexit/mergerfs.git
Browse Source
Rework credential handling to support chroot & idmap (#1595)
Rework credential handling to support chroot & idmap (#1595)
Run in an elevated credential mode (root) and let the kernel manage entitlements. Will result in slightly different behavior but should not be noticed by most.pull/1598/head
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
69 changed files with 789 additions and 1067 deletions
-
1Makefile
-
19libfuse/lib/fuse_lowlevel.cpp
-
9mkdocs/docs/config/options.md
-
44mkdocs/docs/faq/compatibility_and_integration.md
-
56mkdocs/docs/faq/recommendations_and_warnings.md
-
88mkdocs/docs/faq/technical_behavior_and_limitations.md
-
21mkdocs/docs/faq/usage_and_functionality.md
-
35mkdocs/docs/known_issues_bugs.md
-
1mkdocs/docs/resource_usage.md
-
2mkdocs/docs/runtime_interface.md
-
1mkdocs/mkdocs.yml
-
104src/caps.cpp
-
6src/caps.hpp
-
8src/config.cpp
-
3src/config.hpp
-
65src/config_gidcache.cpp
-
25src/config_gidcache.hpp
-
4src/fs_attr_linux.icpp
-
75src/fs_clonepath.cpp
-
5src/fs_clonepath.hpp
-
2src/fs_is_rofs.hpp
-
49src/fs_mkdir_as.hpp
-
35src/fs_mkdir_as_root.hpp
-
48src/fs_mkdirat.hpp
-
49src/fs_mknod_as.hpp
-
2src/fs_movefile_and_open.cpp
-
56src/fs_open_as.hpp
-
49src/fs_symlink_as.hpp
-
3src/fuse_access.cpp
-
1src/fuse_chmod.cpp
-
3src/fuse_chown.cpp
-
33src/fuse_create.cpp
-
2src/fuse_getattr.cpp
-
2src/fuse_getxattr.cpp
-
1src/fuse_init.cpp
-
7src/fuse_ioctl.cpp
-
9src/fuse_link.cpp
-
2src/fuse_listxattr.cpp
-
39src/fuse_mkdir.cpp
-
39src/fuse_mknod.cpp
-
2src/fuse_open.cpp
-
4src/fuse_passthrough.hpp
-
12src/fuse_readdir_cor.cpp
-
10src/fuse_readdir_cosr.cpp
-
7src/fuse_readdir_cosr_getdents.icpp
-
7src/fuse_readdir_cosr_readdir.icpp
-
3src/fuse_readdir_seq.cpp
-
3src/fuse_readlink.cpp
-
2src/fuse_removexattr.cpp
-
12src/fuse_rename.cpp
-
1src/fuse_rmdir.cpp
-
7src/fuse_setxattr.cpp
-
1src/fuse_statfs.cpp
-
4src/fuse_statx_supported.icpp
-
64src/fuse_symlink.cpp
-
3src/fuse_truncate.cpp
-
3src/fuse_unlink.cpp
-
3src/fuse_utimens.cpp
-
181src/gidcache.cpp
-
50src/gidcache.hpp
-
11src/mergerfs.cpp
-
2src/policy_ff.cpp
-
4src/predictability.h
-
33src/ugid.cpp
-
111src/ugid.hpp
-
128src/ugid_linux.hpp
-
34src/ugid_linux.icpp
-
106src/ugid_rwlock.hpp
-
45src/ugid_rwlock.icpp
@ -1,56 +0,0 @@ |
|||||
# Recommendations and Warnings |
|
||||
|
|
||||
## What should mergerfs NOT be used for? |
|
||||
|
|
||||
* Situations where you need large amounts of contiguous space beyond |
|
||||
that available on any singular device. Such as putting 10GiB file on |
|
||||
2 6GiB filesystems. |
|
||||
* databases: Even if the database stored data in separate files |
|
||||
(mergerfs wouldn't offer much otherwise) the higher latency of the |
|
||||
indirection will really harm performance. If it is a lightly used |
|
||||
sqlite3 database then it should be fine. |
|
||||
* VM images: For the same reasons as databases. VM images are accessed |
|
||||
very aggressively and mergerfs will introduce a lot of extra latency. |
|
||||
* As replacement for RAID: mergerfs is just for pooling branches. If |
|
||||
you need device performance aggregation or high availability you |
|
||||
should stick with RAID. However, it is fine to put a filesystem |
|
||||
which is on a RAID setup in mergerfs. |
|
||||
|
|
||||
**However, if using [passthrough](../config/passthrough.md) the |
|
||||
performance related issues above are less likely to be a concern. Best |
|
||||
to do testing for your specific use case.** |
|
||||
|
|
||||
|
|
||||
## It's mentioned that there are some security issues with mhddfs. What are they? How does mergerfs address them? |
|
||||
|
|
||||
[mhddfs](https://github.com/trapexit/mhddfs) manages running as |
|
||||
`root` by calling |
|
||||
[getuid()](https://github.com/trapexit/mhddfs/blob/cae96e6251dd91e2bdc24800b4a18a74044f6672/src/main.c#L319) |
|
||||
and if it returns `0` then it will |
|
||||
[chown](http://linux.die.net/man/1/chown) the file. Not only is that a |
|
||||
race condition but it doesn't handle other situations. Rather than |
|
||||
attempting to simulate POSIX ACL behavior the proper way to manage |
|
||||
this is to use [seteuid](http://linux.die.net/man/2/seteuid) and |
|
||||
[setegid](http://linux.die.net/man/2/setegid), in effect, becoming the |
|
||||
user making the original call, and perform the action as them. This is |
|
||||
what mergerfs does and why mergerfs should always run as root. |
|
||||
|
|
||||
In Linux setreuid syscalls apply only to the thread. glibc hides this |
|
||||
away by using realtime signals to inform all threads to change |
|
||||
credentials. Taking after Samba, mergerfs uses |
|
||||
`syscall(SYS_setreuid,...)` to set the callers credentials for that |
|
||||
thread only. Jumping back to `root` as necessary should escalated |
|
||||
privileges be needed (for instance: to clone paths between |
|
||||
filesystems). |
|
||||
|
|
||||
For non-Linux systems, mergerfs uses a read-write lock and changes |
|
||||
credentials only when necessary. If multiple threads are to be user X |
|
||||
then only the first one will need to change the processes |
|
||||
credentials. So long as the other threads need to be user X they will |
|
||||
take a readlock allowing multiple threads to share the |
|
||||
credentials. Once a request comes in to run as user Y that thread will |
|
||||
attempt a write lock and change to Y's credentials when it can. If the |
|
||||
ability to give writers priority is supported then that flag will be |
|
||||
used so threads trying to change credentials don't starve. This isn't |
|
||||
the best solution but should work reasonably well assuming there are |
|
||||
few users. |
|
||||
@ -0,0 +1,104 @@ |
|||||
|
#include "caps.hpp"
|
||||
|
|
||||
|
#if defined __linux__
|
||||
|
|
||||
|
#include <stdio.h>
|
||||
|
#include <stdlib.h>
|
||||
|
#include <unistd.h>
|
||||
|
#include <sys/prctl.h>
|
||||
|
#include <sys/types.h>
|
||||
|
#include <sys/stat.h>
|
||||
|
#include <sys/syscall.h>
|
||||
|
#include <fcntl.h>
|
||||
|
#include <errno.h>
|
||||
|
#include <string.h>
|
||||
|
#include <grp.h>
|
||||
|
#include <linux/capability.h>
|
||||
|
#include <linux/securebits.h>
|
||||
|
|
||||
|
|
||||
|
static |
||||
|
int |
||||
|
capset(cap_user_header_t header_, |
||||
|
const cap_user_data_t data_) |
||||
|
{ |
||||
|
return ::syscall(SYS_capset,header_,data_); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
capget(cap_user_header_t header_, |
||||
|
cap_user_data_t data_) |
||||
|
{ |
||||
|
return ::syscall(SYS_capget,header_,data_); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
capset(int cap_bit_) |
||||
|
{ |
||||
|
int rv; |
||||
|
struct __user_cap_header_struct header; |
||||
|
struct __user_cap_data_struct data[2]; |
||||
|
|
||||
|
header.version = _LINUX_CAPABILITY_VERSION_3; |
||||
|
header.pid = 0; |
||||
|
|
||||
|
rv = capget(&header,data); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
int word = cap_bit_ / 32; |
||||
|
int bit = cap_bit_ % 32; |
||||
|
|
||||
|
data[word].permitted |= (1 << bit); |
||||
|
data[word].effective |= (1 << bit); |
||||
|
data[word].inheritable |= (1 << bit); |
||||
|
|
||||
|
rv = capset(&header,data); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
caps::setup() |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
rv = capset(CAP_DAC_OVERRIDE); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
rv = capset(CAP_DAC_READ_SEARCH); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
rv = capset(CAP_FOWNER); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
rv = capset(CAP_CHOWN); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
rv = capset(CAP_SETUID); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
rv = capset(CAP_SETGID); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
rv = prctl(PR_SET_SECUREBITS, |
||||
|
SECBIT_KEEP_CAPS | SECBIT_NO_SETUID_FIXUP); |
||||
|
if(rv < 0) |
||||
|
return -errno; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
#else
|
||||
|
#include <errno.h>
|
||||
|
|
||||
|
int |
||||
|
caps::setup() |
||||
|
{ |
||||
|
return -ENOSYS; |
||||
|
} |
||||
|
#endif
|
||||
@ -0,0 +1,6 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
namespace caps |
||||
|
{ |
||||
|
int setup(); |
||||
|
} |
||||
@ -1,65 +0,0 @@ |
|||||
#include "config_gidcache.hpp"
|
|
||||
|
|
||||
#include "gidcache.hpp"
|
|
||||
|
|
||||
#include "to_string.hpp"
|
|
||||
#include "from_string.hpp"
|
|
||||
|
|
||||
|
|
||||
GIDCacheExpireTimeout::GIDCacheExpireTimeout(const int i_) |
|
||||
{ |
|
||||
GIDCache::expire_timeout = i_; |
|
||||
} |
|
||||
|
|
||||
GIDCacheExpireTimeout::GIDCacheExpireTimeout(const std::string &s_) |
|
||||
{ |
|
||||
from_string(s_); |
|
||||
} |
|
||||
|
|
||||
std::string |
|
||||
GIDCacheExpireTimeout::to_string(void) const |
|
||||
{ |
|
||||
return str::to(GIDCache::expire_timeout); |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
GIDCacheExpireTimeout::from_string(const std::string_view s_) |
|
||||
{ |
|
||||
int rv; |
|
||||
|
|
||||
rv = str::from(s_,&GIDCache::expire_timeout); |
|
||||
if(rv < 0) |
|
||||
return rv; |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
GIDCacheRemoveTimeout::GIDCacheRemoveTimeout(const int i_) |
|
||||
{ |
|
||||
GIDCache::remove_timeout = i_; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
GIDCacheRemoveTimeout::GIDCacheRemoveTimeout(const std::string &s_) |
|
||||
{ |
|
||||
from_string(s_); |
|
||||
} |
|
||||
|
|
||||
std::string |
|
||||
GIDCacheRemoveTimeout::to_string(void) const |
|
||||
{ |
|
||||
return str::to(GIDCache::remove_timeout); |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
GIDCacheRemoveTimeout::from_string(const std::string_view s_) |
|
||||
{ |
|
||||
int rv; |
|
||||
|
|
||||
rv = str::from(s_,&GIDCache::remove_timeout); |
|
||||
if(rv < 0) |
|
||||
return rv; |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
@ -1,25 +0,0 @@ |
|||||
#pragma once
|
|
||||
|
|
||||
#include "tofrom_string.hpp"
|
|
||||
|
|
||||
class GIDCacheExpireTimeout : public ToFromString |
|
||||
{ |
|
||||
public: |
|
||||
GIDCacheExpireTimeout(const int i = 60 * 60); |
|
||||
GIDCacheExpireTimeout(const std::string &); |
|
||||
|
|
||||
public: |
|
||||
std::string to_string(void) const final; |
|
||||
int from_string(const std::string_view) final; |
|
||||
}; |
|
||||
|
|
||||
class GIDCacheRemoveTimeout : public ToFromString |
|
||||
{ |
|
||||
public: |
|
||||
GIDCacheRemoveTimeout(const int = 60 * 60 * 12); |
|
||||
GIDCacheRemoveTimeout(const std::string &); |
|
||||
|
|
||||
public: |
|
||||
std::string to_string(void) const final; |
|
||||
int from_string(const std::string_view) final; |
|
||||
}; |
|
||||
@ -0,0 +1,49 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include "fs_mkdir.hpp"
|
||||
|
#include "ugid.hpp"
|
||||
|
|
||||
|
|
||||
|
#if defined __linux__
|
||||
|
namespace fs |
||||
|
{ |
||||
|
template<typename T> |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mkdir_as(const ugid_t ugid_, |
||||
|
const T &path_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
const ugid::SetGuard _(ugid_); |
||||
|
|
||||
|
return fs::mkdir(path_,mode_); |
||||
|
} |
||||
|
} |
||||
|
#elif defined __FreeBSD__
|
||||
|
#include "fs_lchown.hpp"
|
||||
|
|
||||
|
namespace fs |
||||
|
{ |
||||
|
template<typename T> |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mkdir_as(const ugid_t ugid_, |
||||
|
const T &path_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
rv = fs::mkdir(path_,mode_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
fs::lchown(path_,ugid_.uid,ugid_.gid); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
#else
|
||||
|
#error "Not Supported"
|
||||
|
#endif
|
||||
@ -1,35 +0,0 @@ |
|||||
/*
|
|
||||
ISC License |
|
||||
|
|
||||
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#include "fs_mkdir.hpp"
|
|
||||
#include "ugid.hpp"
|
|
||||
|
|
||||
namespace fs |
|
||||
{ |
|
||||
template<typename T> |
|
||||
static |
|
||||
inline |
|
||||
int |
|
||||
mkdir_as_root(const T &path_, |
|
||||
const mode_t mode_) |
|
||||
{ |
|
||||
const ugid::SetRootGuard guard; |
|
||||
|
|
||||
return fs::mkdir(path_,mode_); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,48 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include "to_neg_errno.hpp"
|
||||
|
#include "fs_path.hpp"
|
||||
|
|
||||
|
#include <fcntl.h>
|
||||
|
#include <sys/stat.h>
|
||||
|
|
||||
|
namespace fs |
||||
|
{ |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mkdirat(const int dirfd_, |
||||
|
const char *pathname_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
rv = ::mkdirat(dirfd_,pathname_,mode_); |
||||
|
|
||||
|
return ::to_neg_errno(rv); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mkdirat(const int dirfd_, |
||||
|
const std::string &pathname_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
return fs::mkdirat(dirfd_, |
||||
|
pathname_.c_str(), |
||||
|
mode_); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mkdirat(const int dirfd_, |
||||
|
const fs::path &pathname_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
return fs::mkdirat(dirfd_, |
||||
|
pathname_.c_str(), |
||||
|
mode_); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include "fs_mknod.hpp"
|
||||
|
#include "ugid.hpp"
|
||||
|
|
||||
|
|
||||
|
#if defined __linux__
|
||||
|
namespace fs |
||||
|
{ |
||||
|
template<typename T> |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mknod_as(const ugid_t ugid_, |
||||
|
const T &path_, |
||||
|
const mode_t mode_, |
||||
|
const dev_t dev_) |
||||
|
{ |
||||
|
const ugid::SetGuard _(ugid_); |
||||
|
|
||||
|
return fs::mknod(path_,mode_,dev_); |
||||
|
} |
||||
|
} |
||||
|
#elif defined __FreeBSD__
|
||||
|
#include "fs_lchown.hpp"
|
||||
|
|
||||
|
namespace fs |
||||
|
{ |
||||
|
template<typename T> |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
mknod_as(const ugid_t ugid_, |
||||
|
const T &path_, |
||||
|
const mode_t mode_, |
||||
|
const dev_t dev_) |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
rv = fs::mknod(path_,mode_,dev_); |
||||
|
|
||||
|
fs::lchown(path_,ugid_.uid,ugid_.gid); |
||||
|
|
||||
|
return rv; |
||||
|
} |
||||
|
} |
||||
|
#else
|
||||
|
#error "Not Supported!"
|
||||
|
#endif
|
||||
@ -0,0 +1,56 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include "fs_open.hpp"
|
||||
|
#include "ugid.hpp"
|
||||
|
|
||||
|
// Linux can set ugid because it allows for credentials per
|
||||
|
// thread. FreeBSD however does not and must create as root then
|
||||
|
// chown. Another option for both platforms would be to create a temp
|
||||
|
// file, chown, then rename to target. Unfortunately, depending on if
|
||||
|
// the target filesystem is POSIX compliant or uses POSIX / extended
|
||||
|
// ACLs it is not possible to know what is best.
|
||||
|
|
||||
|
|
||||
|
#if defined __linux__
|
||||
|
namespace fs |
||||
|
{ |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
open_as(const ugid_t ugid_, |
||||
|
const fs::path &path_, |
||||
|
const int flags_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
const ugid::SetGuard _(ugid_); |
||||
|
|
||||
|
return fs::open(path_,flags_,mode_); |
||||
|
} |
||||
|
} |
||||
|
#elif defined __FreeBSD__
|
||||
|
#include "fs_fchown.hpp"
|
||||
|
|
||||
|
namespace fs |
||||
|
{ |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
open_as(const ugid_t ugid_, |
||||
|
const fs::path &path_, |
||||
|
const int flags_, |
||||
|
const mode_t mode_) |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
rv = fs::open(path_,flags_,mode_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
fs::fchown(rv,ugid_.uid,ugid_.gid); |
||||
|
|
||||
|
return rv; |
||||
|
} |
||||
|
} |
||||
|
#else
|
||||
|
#error "Not Supported!"
|
||||
|
#endif
|
||||
@ -0,0 +1,49 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include "fs_symlink.hpp"
|
||||
|
#include "ugid.hpp"
|
||||
|
|
||||
|
|
||||
|
#if defined __linux__
|
||||
|
namespace fs |
||||
|
{ |
||||
|
template<typename T> |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
symlink_as(const ugid_t ugid_, |
||||
|
const char *target_, |
||||
|
const T &linkpath_) |
||||
|
{ |
||||
|
const ugid::SetGuard _(ugid_); |
||||
|
|
||||
|
return fs::symlink(target_,linkpath_); |
||||
|
} |
||||
|
} |
||||
|
#elif defined __FreeBSD__
|
||||
|
#include "fs_lchown.hpp"
|
||||
|
|
||||
|
namespace fs |
||||
|
{ |
||||
|
template<typename T> |
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
symlink_as(const ugid_t ugid_, |
||||
|
const char *target_, |
||||
|
const T &linkpath_) |
||||
|
{ |
||||
|
int rv; |
||||
|
|
||||
|
rv = fs::symlink(target_,linkpath_); |
||||
|
if(rv < 0) |
||||
|
return rv; |
||||
|
|
||||
|
fs::lchown(linkpath_,ugid_.uid,ugid_.gid); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
#else
|
||||
|
#error "Not Supported!"
|
||||
|
#endif
|
||||
@ -1,181 +0,0 @@ |
|||||
/*
|
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#include "gidcache.hpp"
|
|
||||
|
|
||||
#include "syslog.hpp"
|
|
||||
|
|
||||
#include <grp.h>
|
|
||||
#include <pwd.h>
|
|
||||
#include <stdlib.h>
|
|
||||
#include <sys/types.h>
|
|
||||
#include <unistd.h>
|
|
||||
|
|
||||
#if defined __linux__ and UGID_USE_RWLOCK == 0
|
|
||||
# include <sys/syscall.h>
|
|
||||
#elif __APPLE__
|
|
||||
# include <sys/param.h>
|
|
||||
#endif
|
|
||||
|
|
||||
int GIDCache::expire_timeout = (60 * 60); |
|
||||
int GIDCache::remove_timeout = (60 * 60 * 12); |
|
||||
boost::concurrent_flat_map<uid_t,GIDRecord> GIDCache::_records; |
|
||||
|
|
||||
static |
|
||||
int |
|
||||
_getgrouplist(const char *user, |
|
||||
const gid_t group, |
|
||||
gid_t *groups, |
|
||||
int *ngroups) |
|
||||
{ |
|
||||
#if __APPLE__
|
|
||||
return ::getgrouplist(user,group,(int*)groups,ngroups); |
|
||||
#else
|
|
||||
return ::getgrouplist(user,group,groups,ngroups); |
|
||||
#endif
|
|
||||
} |
|
||||
|
|
||||
static |
|
||||
inline |
|
||||
int |
|
||||
_setgroups(const std::vector<gid_t> gids_) |
|
||||
{ |
|
||||
if(gids_.empty()) |
|
||||
return 0; |
|
||||
|
|
||||
#if defined __linux__ and UGID_USE_RWLOCK == 0
|
|
||||
# if defined SYS_setgroups32
|
|
||||
return ::syscall(SYS_setgroups32,gids_.size(),gids_.data()); |
|
||||
# else
|
|
||||
return ::syscall(SYS_setgroups,gids_.size(),gids_.data()); |
|
||||
# endif
|
|
||||
#else
|
|
||||
return ::setgroups(gids_.size(),gids_.data()); |
|
||||
#endif
|
|
||||
} |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
_getgroups(const uid_t uid_, |
|
||||
const gid_t gid_, |
|
||||
std::vector<gid_t> &gids_) |
|
||||
{ |
|
||||
int rv; |
|
||||
int ngroups; |
|
||||
char buf[4096]; |
|
||||
struct passwd pwd; |
|
||||
struct passwd *pwdrv; |
|
||||
|
|
||||
gids_.clear(); |
|
||||
rv = ::getpwuid_r(uid_,&pwd,buf,sizeof(buf),&pwdrv); |
|
||||
if((rv == -1) || (pwdrv == NULL)) |
|
||||
goto error; |
|
||||
|
|
||||
ngroups = 0; |
|
||||
rv = ::_getgrouplist(pwd.pw_name,gid_,NULL,&ngroups); |
|
||||
gids_.resize(ngroups); |
|
||||
|
|
||||
rv = ::_getgrouplist(pwd.pw_name,gid_,gids_.data(),&ngroups); |
|
||||
if((size_t)ngroups < gids_.size()) |
|
||||
gids_.resize(ngroups); |
|
||||
|
|
||||
return; |
|
||||
|
|
||||
error: |
|
||||
gids_.clear(); |
|
||||
//gids_.push_back(gid_);
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
int |
|
||||
GIDCache::initgroups(const uid_t uid_, |
|
||||
const gid_t gid_) |
|
||||
{ |
|
||||
auto first_func = |
|
||||
[=](auto &x) |
|
||||
{ |
|
||||
x.second.last_update = ::time(NULL); |
|
||||
::_getgroups(uid_,gid_,x.second.gids); |
|
||||
::_setgroups(x.second.gids); |
|
||||
}; |
|
||||
auto exists_func = |
|
||||
[=](auto &x) |
|
||||
{ |
|
||||
time_t now; |
|
||||
|
|
||||
now = ::time(NULL); |
|
||||
if((now - x.second.last_update) > GIDCache::expire_timeout) |
|
||||
{ |
|
||||
::_getgroups(uid_,gid_,x.second.gids); |
|
||||
x.second.last_update = now; |
|
||||
} |
|
||||
::_setgroups(x.second.gids); |
|
||||
}; |
|
||||
|
|
||||
_records.try_emplace_and_visit(uid_, |
|
||||
first_func, |
|
||||
exists_func); |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
GIDCache::invalidate_all() |
|
||||
{ |
|
||||
size_t size; |
|
||||
|
|
||||
size = _records.size(); |
|
||||
_records.visit_all([](auto &x) |
|
||||
{ |
|
||||
x.second.last_update = 0; |
|
||||
}); |
|
||||
|
|
||||
SysLog::info("gid cache invalidated, {} entries",size); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
GIDCache::clear_all() |
|
||||
{ |
|
||||
size_t size; |
|
||||
|
|
||||
size = _records.size(); |
|
||||
_records.clear(); |
|
||||
|
|
||||
SysLog::info("gid cache cleared, {} entries",size); |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
GIDCache::clear_unused() |
|
||||
{ |
|
||||
int erased = 0; |
|
||||
time_t now = ::time(NULL); |
|
||||
auto erase_func = |
|
||||
[now,&erased](auto &x) |
|
||||
{ |
|
||||
bool should_erase; |
|
||||
time_t time_delta; |
|
||||
|
|
||||
time_delta = (now - x.second.last_update); |
|
||||
should_erase = (time_delta > GIDCache::remove_timeout); |
|
||||
erased += should_erase; |
|
||||
|
|
||||
return should_erase; |
|
||||
}; |
|
||||
|
|
||||
_records.erase_if(erase_func); |
|
||||
|
|
||||
SysLog::info("cleared {} unused gid cache entries",erased); |
|
||||
} |
|
||||
@ -1,50 +0,0 @@ |
|||||
/*
|
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#pragma once
|
|
||||
|
|
||||
#include "boost/unordered/concurrent_flat_map.hpp"
|
|
||||
|
|
||||
#include <sys/types.h>
|
|
||||
#include <unistd.h>
|
|
||||
|
|
||||
#include <vector>
|
|
||||
|
|
||||
struct GIDRecord |
|
||||
{ |
|
||||
std::vector<gid_t> gids; |
|
||||
time_t last_update; |
|
||||
}; |
|
||||
|
|
||||
struct GIDCache |
|
||||
{ |
|
||||
public: |
|
||||
static |
|
||||
int |
|
||||
initgroups(const uid_t uid, |
|
||||
const gid_t gid); |
|
||||
|
|
||||
static void invalidate_all(); |
|
||||
static void clear_all(); |
|
||||
static void clear_unused(); |
|
||||
|
|
||||
public: |
|
||||
static int expire_timeout; |
|
||||
static int remove_timeout; |
|
||||
|
|
||||
private: |
|
||||
static boost::concurrent_flat_map<uid_t,GIDRecord> _records; |
|
||||
}; |
|
||||
@ -0,0 +1,4 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#define likely(x) __builtin_expect(!!(x), 1) |
||||
|
#define unlikely(x) __builtin_expect(!!(x), 0) |
||||
@ -1,33 +1,8 @@ |
|||||
/*
|
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#include "gidcache.hpp"
|
|
||||
|
|
||||
#if defined __linux__ and UGID_USE_RWLOCK == 0
|
|
||||
#include "ugid_linux.icpp"
|
|
||||
#else
|
|
||||
#include "ugid_rwlock.icpp"
|
|
||||
#endif
|
|
||||
|
#include <unistd.h>
|
||||
|
|
||||
namespace ugid |
namespace ugid |
||||
{ |
{ |
||||
void |
|
||||
initgroups(const uid_t uid_, |
|
||||
const gid_t gid_) |
|
||||
{ |
|
||||
GIDCache::initgroups(uid_,gid_); |
|
||||
} |
|
||||
|
thread_local uid_t currentuid = 0; |
||||
|
thread_local gid_t currentgid = 0; |
||||
|
thread_local bool initialized = false; |
||||
} |
} |
||||
@ -1,128 +0,0 @@ |
|||||
/*
|
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#pragma once
|
|
||||
|
|
||||
#include "fuse_req_ctx.h"
|
|
||||
|
|
||||
#include <assert.h>
|
|
||||
#include <sys/stat.h>
|
|
||||
#include <sys/syscall.h>
|
|
||||
#include <sys/types.h>
|
|
||||
#include <unistd.h>
|
|
||||
|
|
||||
#include <grp.h>
|
|
||||
#include <pwd.h>
|
|
||||
|
|
||||
#include <map>
|
|
||||
#include <vector>
|
|
||||
|
|
||||
#if defined SYS_setreuid32
|
|
||||
#define SETREUID(R,E) (::syscall(SYS_setreuid32,(R),(E)))
|
|
||||
#else
|
|
||||
#define SETREUID(R,E) (::syscall(SYS_setreuid,(R),(E)))
|
|
||||
#endif
|
|
||||
|
|
||||
#if defined SYS_setregid32
|
|
||||
#define SETREGID(R,E) (::syscall(SYS_setregid32,(R),(E)))
|
|
||||
#else
|
|
||||
#define SETREGID(R,E) (::syscall(SYS_setregid,(R),(E)))
|
|
||||
#endif
|
|
||||
|
|
||||
#if defined SYS_geteuid32
|
|
||||
#define GETEUID() (::syscall(SYS_geteuid32))
|
|
||||
#else
|
|
||||
#define GETEUID() (::syscall(SYS_geteuid))
|
|
||||
#endif
|
|
||||
|
|
||||
#if defined SYS_getegid32
|
|
||||
#define GETEGID() (::syscall(SYS_getegid32))
|
|
||||
#else
|
|
||||
#define GETEGID() (::syscall(SYS_getegid))
|
|
||||
#endif
|
|
||||
|
|
||||
namespace ugid |
|
||||
{ |
|
||||
extern thread_local uid_t currentuid; |
|
||||
extern thread_local gid_t currentgid; |
|
||||
extern thread_local bool initialized; |
|
||||
|
|
||||
struct Set |
|
||||
{ |
|
||||
Set(const uid_t newuid_, |
|
||||
const gid_t newgid_) |
|
||||
{ |
|
||||
assert((int)newuid_ != -1); |
|
||||
assert((int)newgid_ != -1); |
|
||||
|
|
||||
if(!initialized) |
|
||||
{ |
|
||||
currentuid = GETEUID(); |
|
||||
currentgid = GETEGID(); |
|
||||
initialized = true; |
|
||||
} |
|
||||
|
|
||||
if((newuid_ == currentuid) && (newgid_ == currentgid)) |
|
||||
return; |
|
||||
|
|
||||
if(currentuid != 0) |
|
||||
{ |
|
||||
SETREUID(-1,0); |
|
||||
SETREGID(-1,0); |
|
||||
} |
|
||||
|
|
||||
if(newgid_) |
|
||||
{ |
|
||||
SETREGID(-1,newgid_); |
|
||||
ugid::initgroups(newuid_,newgid_); |
|
||||
} |
|
||||
|
|
||||
if(newuid_) |
|
||||
SETREUID(-1,newuid_); |
|
||||
|
|
||||
currentuid = newuid_; |
|
||||
currentgid = newgid_; |
|
||||
} |
|
||||
|
|
||||
Set(const fuse_req_ctx_t *ctx_) |
|
||||
: Set(ctx_->uid,ctx_->gid) |
|
||||
{ |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
struct SetRootGuard |
|
||||
{ |
|
||||
SetRootGuard() : |
|
||||
prevuid(currentuid), |
|
||||
prevgid(currentgid) |
|
||||
{ |
|
||||
Set(0,0); |
|
||||
} |
|
||||
|
|
||||
~SetRootGuard() |
|
||||
{ |
|
||||
Set(prevuid,prevgid); |
|
||||
} |
|
||||
|
|
||||
const uid_t prevuid; |
|
||||
const gid_t prevgid; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
#undef SETREUID
|
|
||||
#undef SETREGID
|
|
||||
#undef GETEUID
|
|
||||
#undef GETEGID
|
|
||||
@ -1,34 +0,0 @@ |
|||||
/* |
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#include <stdlib.h> |
|
||||
#include <sys/syscall.h> |
|
||||
#include <sys/types.h> |
|
||||
#include <unistd.h> |
|
||||
|
|
||||
#include <vector> |
|
||||
|
|
||||
namespace ugid |
|
||||
{ |
|
||||
thread_local uid_t currentuid = 0; |
|
||||
thread_local gid_t currentgid = 0; |
|
||||
thread_local bool initialized = false; |
|
||||
|
|
||||
void |
|
||||
init() |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
@ -1,106 +0,0 @@ |
|||||
/*
|
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#pragma once
|
|
||||
|
|
||||
#include "fuse_req_ctx.h"
|
|
||||
|
|
||||
#include <pthread.h>
|
|
||||
#include <sys/stat.h>
|
|
||||
#include <sys/types.h>
|
|
||||
#include <unistd.h>
|
|
||||
|
|
||||
namespace ugid |
|
||||
{ |
|
||||
extern uid_t currentuid; |
|
||||
extern gid_t currentgid; |
|
||||
extern pthread_rwlock_t rwlock; |
|
||||
|
|
||||
static |
|
||||
void |
|
||||
ugid_set(const uid_t newuid_, |
|
||||
const gid_t newgid_) |
|
||||
{ |
|
||||
pthread_rwlock_rdlock(&rwlock); |
|
||||
|
|
||||
if((newuid_ == currentuid) && (newgid_ == currentgid)) |
|
||||
return; |
|
||||
|
|
||||
pthread_rwlock_unlock(&rwlock); |
|
||||
pthread_rwlock_wrlock(&rwlock); |
|
||||
|
|
||||
if((newuid_ == currentuid) && (newgid_ == currentgid)) |
|
||||
return; |
|
||||
|
|
||||
if(currentuid != 0) |
|
||||
{ |
|
||||
::seteuid(0); |
|
||||
::setegid(0); |
|
||||
} |
|
||||
|
|
||||
if(newgid_) |
|
||||
{ |
|
||||
::setegid(newgid_); |
|
||||
initgroups(newuid_,newgid_); |
|
||||
} |
|
||||
|
|
||||
if(newuid_) |
|
||||
::seteuid(newuid_); |
|
||||
|
|
||||
currentuid = newuid_; |
|
||||
currentgid = newgid_; |
|
||||
} |
|
||||
|
|
||||
struct Set |
|
||||
{ |
|
||||
Set(const uid_t newuid_, |
|
||||
const gid_t newgid_) |
|
||||
{ |
|
||||
ugid_set(newuid_,newgid_); |
|
||||
} |
|
||||
|
|
||||
Set(const fuse_req_ctx_t *ctx_) |
|
||||
: Set(ctx_->uid,ctx_->gid) |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
~Set() |
|
||||
{ |
|
||||
pthread_rwlock_unlock(&rwlock); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
struct SetRootGuard |
|
||||
{ |
|
||||
SetRootGuard() : |
|
||||
prevuid(currentuid), |
|
||||
prevgid(currentgid) |
|
||||
{ |
|
||||
pthread_rwlock_unlock(&rwlock); |
|
||||
ugid_set(0,0); |
|
||||
} |
|
||||
|
|
||||
~SetRootGuard() |
|
||||
{ |
|
||||
pthread_rwlock_unlock(&rwlock); |
|
||||
ugid_set(prevuid,prevgid); |
|
||||
} |
|
||||
|
|
||||
const uid_t prevuid; |
|
||||
const gid_t prevgid; |
|
||||
}; |
|
||||
} |
|
||||
@ -1,45 +0,0 @@ |
|||||
/* |
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link> |
|
||||
|
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
|
||||
purpose with or without fee is hereby granted, provided that the above |
|
||||
copyright notice and this permission notice appear in all copies. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
||||
*/ |
|
||||
|
|
||||
#include <pthread.h> |
|
||||
#include <stdlib.h> |
|
||||
#include <sys/types.h> |
|
||||
#include <unistd.h> |
|
||||
|
|
||||
#include <vector> |
|
||||
|
|
||||
namespace ugid |
|
||||
{ |
|
||||
uid_t currentuid; |
|
||||
gid_t currentgid; |
|
||||
pthread_rwlock_t rwlock; |
|
||||
|
|
||||
void |
|
||||
init() |
|
||||
{ |
|
||||
pthread_rwlockattr_t attr; |
|
||||
|
|
||||
pthread_rwlockattr_init(&attr); |
|
||||
# if defined PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP |
|
||||
pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); |
|
||||
# endif |
|
||||
|
|
||||
pthread_rwlock_init(&rwlock,&attr); |
|
||||
|
|
||||
currentuid = ::geteuid(); |
|
||||
currentgid = ::getegid(); |
|
||||
} |
|
||||
} |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue