diff --git a/Userland/Libraries/LibCore/Group.cpp b/Userland/Libraries/LibCore/Group.cpp index e97d1eaf2e..4649324188 100644 --- a/Userland/Libraries/LibCore/Group.cpp +++ b/Userland/Libraries/LibCore/Group.cpp @@ -6,13 +6,71 @@ #include #include +#include #include #include #include +#include #include +#include namespace Core { +ErrorOr Group::generate_group_file() const +{ + StringBuilder builder; + + ScopeGuard grent_guard([] { endgrent(); }); + setgrent(); + errno = 0; +#ifndef AK_OS_MACOS + struct group group; + struct group* gr = nullptr; + char buffer[1024] = { 0 }; + while (getgrent_r(&group, buffer, sizeof(buffer), &gr) == 0 && gr) { +#else + for (auto const* gr = getgrent(); gr; gr = getgrent()) { +#endif + if (gr->gr_name == m_name) + builder.appendff("{}:x:{}:{}\n", m_name, m_id, String::join(',', m_members)); + else { + Vector members; + for (size_t i = 0; gr->gr_mem[i]; ++i) + members.append(gr->gr_mem[i]); + + builder.appendff("{}:x:{}:{}\n", gr->gr_name, gr->gr_gid, String::join(',', members)); + } + } + + if (errno) + return Error::from_errno(errno); + + return builder.to_string(); +} + +ErrorOr Group::sync() +{ + Core::UmaskScope umask_scope(0777); + + auto new_group_file_content = TRY(generate_group_file()); + + char new_group_name[] = "/etc/group.XXXXXX"; + size_t new_group_name_length = strlen(new_group_name); + + { + auto new_group_fd = TRY(Core::System::mkstemp({ new_group_name, new_group_name_length })); + ScopeGuard new_group_fd_guard([new_group_fd] { close(new_group_fd); }); + TRY(Core::System::fchmod(new_group_fd, 0664)); + + auto nwritten = TRY(Core::System::write(new_group_fd, new_group_file_content.bytes())); + VERIFY(static_cast(nwritten) == new_group_file_content.length()); + } + + TRY(Core::System::rename({ new_group_name, new_group_name_length }, "/etc/group"sv)); + + return {}; +} + #if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID) ErrorOr Group::add_group(Group& group) { @@ -69,10 +127,17 @@ ErrorOr> Group::all() ScopeGuard grent_guard([] { endgrent(); }); setgrent(); errno = 0; +#ifndef AK_OS_MACOS + struct group group; + struct group* gr = nullptr; + char buffer[1024] = { 0 }; + while (getgrent_r(&group, buffer, sizeof(buffer), &gr) == 0 && gr) { +#else for (auto const* gr = getgrent(); gr; gr = getgrent()) { +#endif Vector members; for (size_t i = 0; gr->gr_mem[i]; ++i) - members.append(*gr->gr_mem); + members.append(gr->gr_mem[i]); groups.append({ gr->gr_name, gr->gr_gid, members }); } diff --git a/Userland/Libraries/LibCore/Group.h b/Userland/Libraries/LibCore/Group.h index 53dcf12d41..05effe678b 100644 --- a/Userland/Libraries/LibCore/Group.h +++ b/Userland/Libraries/LibCore/Group.h @@ -34,11 +34,15 @@ public: Vector& members() { return m_members; } + ErrorOr sync(); + private: static ErrorOr name_exists(StringView name); static ErrorOr id_exists(gid_t id); ErrorOr to_libc_group(); + ErrorOr generate_group_file() const; + String m_name; gid_t m_id { 0 }; Vector m_members;