33 #include <sys/types.h>
34 #include <sys/mount.h>
35 #include <sys/capability.h>
36 #include <sys/prctl.h>
41 static constexpr const bool change_caps =
false;
43 static void print_creds(
const std::string& title) {
44 jau::fprintf_td(stderr,
"%s: uid %" PRIu32
", euid %" PRIu32
", gid %" PRIu32
", egid %" PRIu32
"\n",
45 title.c_str(), ::getuid(), ::geteuid(), ::getgid(), ::getegid());
48 int count = ::getgroups(
sizeof(gid_list)/
sizeof(*gid_list), gid_list);
53 for(
int i=0; i<count; ++i) {
54 fprintf(stderr,
"%" PRIu32
", ", gid_list[i]);
56 fprintf(stderr,
"\n");
60 static bool set_groups(
size_t size,
const gid_t *list) {
61 if( 0 > ::setgroups(size, list) ) {
68 static bool set_effective_gid(::gid_t group_id) {
69 if( 0 != ::setegid(group_id) ) {
70 ERR_PRINT(
"setegid(%" PRIu32
") failed", group_id);
76 static bool set_effective_uid(::uid_t user_id) {
77 if( 0 != ::seteuid(user_id) ) {
78 ERR_PRINT(
"seteuid(%" PRIu32
") failed", user_id);
86 static bool cap_get_flag(cap_t cap_p, cap_value_t cap, cap_flag_t flag, cap_flag_value_t *value_p)
noexcept {
93 static bool cap_set_flag(cap_t cap_p, cap_flag_t flag,
int ncap,
const cap_value_t *caps, cap_flag_value_t value)
noexcept {
101 static bool cap_set_proc_flag(
const std::string& title, cap_flag_t flag,
int ncap,
const cap_value_t *cap_list)
noexcept {
103 cap_p = ::cap_get_proc();
104 if(
nullptr == cap_p ) {
108 if( !
cap_set_flag(cap_p, flag, ncap, cap_list, CAP_SET) ) {
return false; }
109 ::cap_set_proc(cap_p);
111 char* c_str = ::cap_to_text(cap_p,
nullptr);
121 caps = ::cap_get_proc();
122 if(
nullptr == caps ) {
127 char* c_str = ::cap_to_text(caps,
nullptr);
142 static ::gid_t
get_gid(
const std::string& groupname) {
143 static const ::gid_t default_group = 44;
144 std::string cmd(
"getent group "+groupname+
" | cut -d: -f3");
145 FILE* fp = ::popen(cmd.c_str(),
"r");
147 fprintf(stderr,
"Command failed (1) '%s'\n", cmd.c_str() );
148 return default_group;
151 ::gid_t result_int = default_group;
152 if(
nullptr != ::fgets(result,
sizeof(result), fp) ) {
153 result_int =
static_cast<::gid_t
>( ::atoi(result) );
154 jau::PLAIN_PRINT(
true,
"get_gid(%s) -> %s (%d)", groupname.c_str(), result, (
int)result_int);
156 fprintf(stderr,
"Command failed (2) '%s'\n", cmd.c_str() );
163 INFO_STR(
"\n\ntest50_mount_copy_r_p\n");
165 ::cap_value_t cap_list[] = { CAP_SYS_ADMIN, CAP_SETUID, CAP_SETGID };
166 const size_t cap_list_size =
sizeof(cap_list) /
sizeof(*cap_list);
168 const ::uid_t super_uid = 0;
169 ::uid_t caller_uid = ::getuid();
171 ::uid_t user_id = caller_uid;
177 ::gid_t group_id = (::gid_t)user_info.
gid();
178 ::gid_t group_list[] = { user_id, group_id,
get_gid(
"video") };
180 const bool setuid_user_to_root = super_uid != caller_uid;
181 if( setuid_user_to_root ) {
182 print_creds(
"user level - setuid user -> root");
185 caps = ::cap_get_proc();
186 if(
nullptr == caps ) {
191 char* c_str = ::cap_to_text(caps,
nullptr);
195 cap_flag_value_t cap_sys_admin, cap_setuid, cap_setgid;
196 if( !
cap_get_flag(caps, CAP_SYS_ADMIN, ::CAP_EFFECTIVE, &cap_sys_admin) ) {
return; }
197 if( !
cap_get_flag(caps, CAP_SETUID, ::CAP_EFFECTIVE, &cap_setuid) ) {
return; }
198 if( !
cap_get_flag(caps, CAP_SETGID, ::CAP_EFFECTIVE, &cap_setgid) ) {
return; }
200 cap_sys_admin, cap_setuid, cap_setgid);
203 if( 0 > ::prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) ) {
ERR_PRINT(
"prctl() failed"); }
207 if( !cap_sys_admin || !cap_setuid || !cap_setgid ) {
208 ERR_PRINT(
"capabilities incomplete, needs: cap_sys_admin, cap_setuid, cap_setgid, uid is % " PRIu32
"", caller_uid);
212 if( !set_groups(
sizeof(group_list)/
sizeof(*group_list), group_list) ) {
217 print_creds(
"root level - setuid root -> user");
219 if constexpr ( change_caps ) {
221 caps = ::cap_get_proc();
222 if(
nullptr == caps ) {
227 if( !
cap_set_flag(caps, ::CAP_EFFECTIVE, cap_list_size, cap_list, ::CAP_SET) ) {
return; }
228 if( !
cap_set_flag(caps, ::CAP_INHERITABLE, cap_list_size, cap_list, ::CAP_SET) ) {
return; }
229 if( !
cap_set_flag(caps, ::CAP_PERMITTED, cap_list_size, cap_list, ::CAP_SET) ) {
return; }
230 if( !cap_set_proc(caps) ) {
return; }
232 char* c_str = ::cap_to_text(caps,
nullptr);
236 if( 0 > ::prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) ) {
244 if( !set_groups(
sizeof(group_list)/
sizeof(*group_list), group_list) ) {
247 if( !set_effective_gid(group_id) ) {
250 if( !set_effective_uid(user_id) ) {
254 if constexpr ( change_caps ) {
255 if( !
cap_set_proc_flag(
"user level", CAP_EFFECTIVE, cap_list_size, cap_list) ) {
return; }
258 print_creds(
"user level");
259 REQUIRE( user_id == ::geteuid() );
263 REQUIRE(
true == image_stats.
exists() );
265 const std::string mount_point =
temp_root+
"_mount";
271 REQUIRE( user_id == ::geteuid() );
272 print_creds(
"pre-mount");
282 print_creds(
"post-mount");
284 REQUIRE( user_id == ::geteuid() );
286 REQUIRE(
true == mctx.
mounted );
292 const std::string root_copy =
temp_root+
"_copy_test50";
294 testxx_copy_r_p(
"test50_mount_copy_r_p", mount_point, 1 , root_copy, copts,
false );
299 REQUIRE( user_id == ::geteuid() );
300 print_creds(
"pre-umount");
310 print_creds(
"post-umount");
312 REQUIRE( user_id == ::geteuid() );
314 REQUIRE(
true == umount_ok );
std::string executable_path
The main argv[0] test executable path.
static bool cap_get_flag(cap_t cap_p, cap_value_t cap, cap_flag_t flag, cap_flag_value_t *value_p) noexcept
void test50_mount_copy_r_p()
::gid_t get_gid(const std::string &groupname)
Get group-id by groupname using system commands getent and cut.
static bool cap_set_proc_flag(const std::string &title, cap_flag_t flag, int ncap, const cap_value_t *cap_list) noexcept
static void print_caps(const std::string &title)
static bool cap_set_flag(cap_t cap_p, cap_flag_t flag, int ncap, const cap_value_t *caps, cap_flag_value_t value) noexcept
jau::fs::file_stats getTestDataImageFile(const std::string &test_exe_path) noexcept
const std::string temp_root
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
constexpr bool exists() const noexcept
Returns true if entity does not exist, exclusive bit.
std::string path() const noexcept
Returns the unix path representation.
User account information of the underlying OS.
id_t gid() const noexcept
bool isValid() const noexcept
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
bool mkdir(const std::string &path, const fmode_t mode=jau::fs::fmode_t::def_dir_prot, const bool verbose=false) noexcept
Create directory.
uint64_t mountflags_t
Generic flag bit values for mount() flags.
mount_ctx mount_image(const std::string &image_path, const std::string &target, const std::string &fs_type, const mountflags_t flags, const std::string &fs_options="")
Attach the filesystem image named in image_path to target using an intermediate platform specific fil...
int umountflags_t
Generic flag bit values for umount() flags.
copy_options
Filesystem copy options used to copy() path elements.
bool remove(const std::string &path, const traverse_options topts=traverse_options::none) noexcept
Remove the given path.
bool umount(const mount_ctx &context, const umountflags_t flags)
Detach the given mount_ctx context
@ def_dir_prot
Default directory protection bit: Safe default: POSIX S_IRWXU | S_IRGRP | S_IXGRP or rwx_usr | read_g...
@ verbose
Enable verbosity mode, show error messages on stderr.
@ sync
Ensure data and meta-data file synchronization is performed via ::fsync() after asynchronous copy ope...
@ preserve_all
Preserve uid and gid if allowed and access- and modification-timestamps, i.e.
@ recursive
Traverse through directories, i.e.
@ recursive
Traverse through directories, i.e.
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
static constexpr const bool _remove_target_test_dir
void testxx_copy_r_p(const std::string &title, const jau::fs::file_stats &source, const int source_added_dead_links, const std::string &dest, const jau::fs::copy_options copts, const bool dest_is_vfat)
METHOD_AS_TEST_CASE(TestFileUtil02::test50_mount_copy_r_p, "Test TestFileUtil02 - test50_mount_copy_r_p")