34 #include <sys/types.h>
35 #include <sys/mount.h>
36 #include <sys/capability.h>
37 #include <sys/prctl.h>
42 static constexpr const bool change_caps =
false;
44 static void print_creds(
const std::string& title) {
45 jau::fprintf_td(stderr,
"%s: uid %" PRIu32
", euid %" PRIu32
", gid %" PRIu32
", egid %" PRIu32
"\n",
46 title.c_str(), ::getuid(), ::geteuid(), ::getgid(), ::getegid());
49 int count = ::getgroups(
sizeof(gid_list)/
sizeof(*gid_list), gid_list);
54 for(
int i=0; i<count; ++i) {
55 fprintf(stderr,
"%" PRIu32
", ", gid_list[i]);
57 fprintf(stderr,
"\n");
61 static bool set_groups(
size_t size,
const gid_t *list) {
62 if( 0 > ::setgroups(size, list) ) {
69 static bool set_effective_gid(::gid_t group_id) {
70 if( 0 != ::setegid(group_id) ) {
71 ERR_PRINT(
"setegid(%" PRIu32
") failed", group_id);
77 static bool set_effective_uid(::uid_t user_id) {
78 if( 0 != ::seteuid(user_id) ) {
79 ERR_PRINT(
"seteuid(%" PRIu32
") failed", user_id);
87 static bool cap_get_flag(cap_t cap_p, cap_value_t cap, cap_flag_t flag, cap_flag_value_t *value_p)
noexcept {
94 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 {
102 static bool cap_set_proc_flag(
const std::string& title, cap_flag_t flag,
int ncap,
const cap_value_t *cap_list)
noexcept {
104 cap_p = ::cap_get_proc();
105 if(
nullptr == cap_p ) {
109 if( !
cap_set_flag(cap_p, flag, ncap, cap_list, CAP_SET) ) {
return false; }
110 ::cap_set_proc(cap_p);
112 char* c_str = ::cap_to_text(cap_p,
nullptr);
122 caps = ::cap_get_proc();
123 if(
nullptr == caps ) {
128 char* c_str = ::cap_to_text(caps,
nullptr);
143 static ::gid_t
get_gid(
const std::string& groupname) {
144 static const ::gid_t default_group = 44;
145 std::string cmd(
"getent group "+groupname+
" | cut -d: -f3");
146 FILE* fp = ::popen(cmd.c_str(),
"r");
148 fprintf(stderr,
"Command failed (1) '%s'\n", cmd.c_str() );
149 return default_group;
152 ::gid_t result_int = default_group;
153 if(
nullptr != ::fgets(result,
sizeof(result), fp) ) {
154 result_int =
static_cast<::gid_t
>( ::atoi(result) );
155 jau::PLAIN_PRINT(
true,
"get_gid(%s) -> %s (%d)", groupname.c_str(), result, (
int)result_int);
157 fprintf(stderr,
"Command failed (2) '%s'\n", cmd.c_str() );
164 INFO_STR(
"\n\ntest50_mount_copy_r_p\n");
166 ::cap_value_t cap_list[] = { CAP_SYS_ADMIN, CAP_SETUID, CAP_SETGID };
167 const size_t cap_list_size =
sizeof(cap_list) /
sizeof(*cap_list);
169 const ::uid_t super_uid = 0;
170 ::uid_t caller_uid = ::getuid();
172 ::uid_t user_id = caller_uid;
178 ::gid_t group_id = (::gid_t)user_info.
gid();
179 ::gid_t group_list[] = { user_id, group_id,
get_gid(
"video") };
181 const bool setuid_user_to_root = super_uid != caller_uid;
182 if( setuid_user_to_root ) {
183 print_creds(
"user level - setuid user -> root");
186 caps = ::cap_get_proc();
187 if(
nullptr == caps ) {
192 char* c_str = ::cap_to_text(caps,
nullptr);
196 cap_flag_value_t cap_sys_admin, cap_setuid, cap_setgid;
197 if( !
cap_get_flag(caps, CAP_SYS_ADMIN, ::CAP_EFFECTIVE, &cap_sys_admin) ) {
return; }
198 if( !
cap_get_flag(caps, CAP_SETUID, ::CAP_EFFECTIVE, &cap_setuid) ) {
return; }
199 if( !
cap_get_flag(caps, CAP_SETGID, ::CAP_EFFECTIVE, &cap_setgid) ) {
return; }
201 cap_sys_admin, cap_setuid, cap_setgid);
204 if( 0 > ::prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) ) {
ERR_PRINT(
"prctl() failed"); }
208 if( !cap_sys_admin || !cap_setuid || !cap_setgid ) {
209 ERR_PRINT(
"capabilities incomplete, needs: cap_sys_admin, cap_setuid, cap_setgid, uid is % " PRIu32
"", caller_uid);
213 if( !set_groups(
sizeof(group_list)/
sizeof(*group_list), group_list) ) {
218 print_creds(
"root level - setuid root -> user");
220 if constexpr ( change_caps ) {
222 caps = ::cap_get_proc();
223 if(
nullptr == caps ) {
228 if( !
cap_set_flag(caps, ::CAP_EFFECTIVE, cap_list_size, cap_list, ::CAP_SET) ) {
return; }
229 if( !
cap_set_flag(caps, ::CAP_INHERITABLE, cap_list_size, cap_list, ::CAP_SET) ) {
return; }
230 if( !
cap_set_flag(caps, ::CAP_PERMITTED, cap_list_size, cap_list, ::CAP_SET) ) {
return; }
231 if( !cap_set_proc(caps) ) {
return; }
233 char* c_str = ::cap_to_text(caps,
nullptr);
237 if( 0 > ::prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) ) {
245 if( !set_groups(
sizeof(group_list)/
sizeof(*group_list), group_list) ) {
248 if( !set_effective_gid(group_id) ) {
251 if( !set_effective_uid(user_id) ) {
255 if constexpr ( change_caps ) {
256 if( !
cap_set_proc_flag(
"user level", CAP_EFFECTIVE, cap_list_size, cap_list) ) {
return; }
259 print_creds(
"user level");
260 REQUIRE( user_id == ::geteuid() );
264 REQUIRE(
true == image_stats.
exists() );
266 const std::string mount_point =
temp_root+
"_mount";
272 REQUIRE( user_id == ::geteuid() );
273 print_creds(
"pre-mount");
283 print_creds(
"post-mount");
285 REQUIRE( user_id == ::geteuid() );
287 REQUIRE(
true == mctx.
mounted );
293 const std::string root_copy =
temp_root+
"_copy_test50";
295 testxx_copy_r_p(
"test50_mount_copy_r_p", mount_point, 1 , root_copy, copts,
false );
300 REQUIRE( user_id == ::geteuid() );
301 print_creds(
"pre-umount");
311 print_creds(
"post-umount");
313 REQUIRE( user_id == ::geteuid() );
315 REQUIRE(
true == umount_ok );
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: '.
constexpr std::underlying_type_t< E > number(const E v) noexcept
constexpr bool value(const Bool rhs) noexcept
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")