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
const std::string temp_root
jau::io::fs::file_stats getTestDataImageFile(const std::string &test_exe_path) noexcept
Platform agnostic representation of POSIX ::lstat() and ::stat() for a given pathname.
std::string path() const noexcept
Returns the unix path representation.
constexpr bool exists() const noexcept
Returns true if entity does not exist, exclusive bit.
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 umount(const mount_ctx &context, const umountflags_t flags)
Detach the given mount_ctx context
int umountflags_t
Generic flag bit values for umount() 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...
copy_options
Filesystem copy options used to copy() path elements.
bool mkdir(const std::string &path, const fmode_t mode=fmode_t::def_dir_prot, const bool verbose=false) noexcept
Create directory.
bool remove(const std::string &path, const traverse_options topts=traverse_options::none) noexcept
Remove the given path.
uint64_t mountflags_t
Generic flag bit values for mount() flags.
@ 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::io::fs::file_stats &source, const int source_added_dead_links, const std::string &dest, const jau::io::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")