Ver Fonte

LibCore: Enable modification of a user's supplementary groups

Tim Ledbetter há 2 anos atrás
pai
commit
089ff7b94e

+ 48 - 1
Userland/Libraries/LibCore/Account.cpp

@@ -251,6 +251,42 @@ ErrorOr<DeprecatedString> Account::generate_passwd_file() const
     return builder.to_deprecated_string();
     return builder.to_deprecated_string();
 }
 }
 
 
+ErrorOr<DeprecatedString> Account::generate_group_file() const
+{
+    StringBuilder builder;
+    char buffer[1024] = { 0 };
+
+    ScopeGuard pwent_guard([] { endgrent(); });
+    setgrent();
+
+    while (true) {
+        auto group = TRY(Core::System::getgrent(buffer));
+        if (!group.has_value())
+            break;
+
+        auto should_be_present = !m_deleted && m_extra_gids.contains_slow(group->gr_gid);
+
+        auto already_present = false;
+        Vector<char const*> members;
+        for (size_t i = 0; group->gr_mem[i]; ++i) {
+            auto const* member = group->gr_mem[i];
+            if (member == m_username) {
+                already_present = true;
+                if (!should_be_present)
+                    continue;
+            }
+            members.append(member);
+        }
+
+        if (should_be_present && !already_present)
+            members.append(m_username.characters());
+
+        builder.appendff("{}:{}:{}:{}\n", group->gr_name, group->gr_passwd, group->gr_gid, DeprecatedString::join(","sv, members));
+    }
+
+    return builder.to_deprecated_string();
+}
+
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
 ErrorOr<DeprecatedString> Account::generate_shadow_file() const
 ErrorOr<DeprecatedString> Account::generate_shadow_file() const
 {
 {
@@ -291,11 +327,13 @@ ErrorOr<void> Account::sync()
     Core::UmaskScope umask_scope(0777);
     Core::UmaskScope umask_scope(0777);
 
 
     auto new_passwd_file_content = TRY(generate_passwd_file());
     auto new_passwd_file_content = TRY(generate_passwd_file());
+    auto new_group_file_content = TRY(generate_group_file());
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
     auto new_shadow_file_content = TRY(generate_shadow_file());
     auto new_shadow_file_content = TRY(generate_shadow_file());
 #endif
 #endif
 
 
     char new_passwd_file[] = "/etc/passwd.XXXXXX";
     char new_passwd_file[] = "/etc/passwd.XXXXXX";
+    char new_group_file[] = "/etc/group.XXXXXX";
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
     char new_shadow_file[] = "/etc/shadow.XXXXXX";
     char new_shadow_file[] = "/etc/shadow.XXXXXX";
 #endif
 #endif
@@ -305,6 +343,10 @@ ErrorOr<void> Account::sync()
         ScopeGuard new_passwd_fd_guard = [new_passwd_fd] { close(new_passwd_fd); };
         ScopeGuard new_passwd_fd_guard = [new_passwd_fd] { close(new_passwd_fd); };
         TRY(Core::System::fchmod(new_passwd_fd, 0644));
         TRY(Core::System::fchmod(new_passwd_fd, 0644));
 
 
+        auto new_group_fd = TRY(Core::System::mkstemp(new_group_file));
+        ScopeGuard new_group_fd_guard = [new_group_fd] { close(new_group_fd); };
+        TRY(Core::System::fchmod(new_group_fd, 0644));
+
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
         auto new_shadow_fd = TRY(Core::System::mkstemp(new_shadow_file));
         auto new_shadow_fd = TRY(Core::System::mkstemp(new_shadow_file));
         ScopeGuard new_shadow_fd_guard = [new_shadow_fd] { close(new_shadow_fd); };
         ScopeGuard new_shadow_fd_guard = [new_shadow_fd] { close(new_shadow_fd); };
@@ -314,6 +356,9 @@ ErrorOr<void> Account::sync()
         auto nwritten = TRY(Core::System::write(new_passwd_fd, new_passwd_file_content.bytes()));
         auto nwritten = TRY(Core::System::write(new_passwd_fd, new_passwd_file_content.bytes()));
         VERIFY(static_cast<size_t>(nwritten) == new_passwd_file_content.length());
         VERIFY(static_cast<size_t>(nwritten) == new_passwd_file_content.length());
 
 
+        nwritten = TRY(Core::System::write(new_group_fd, new_group_file_content.bytes()));
+        VERIFY(static_cast<size_t>(nwritten) == new_group_file_content.length());
+
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
         nwritten = TRY(Core::System::write(new_shadow_fd, new_shadow_file_content.bytes()));
         nwritten = TRY(Core::System::write(new_shadow_fd, new_shadow_file_content.bytes()));
         VERIFY(static_cast<size_t>(nwritten) == new_shadow_file_content.length());
         VERIFY(static_cast<size_t>(nwritten) == new_shadow_file_content.length());
@@ -322,13 +367,15 @@ ErrorOr<void> Account::sync()
 
 
     auto new_passwd_file_view = StringView { new_passwd_file, sizeof(new_passwd_file) };
     auto new_passwd_file_view = StringView { new_passwd_file, sizeof(new_passwd_file) };
     TRY(Core::System::rename(new_passwd_file_view, "/etc/passwd"sv));
     TRY(Core::System::rename(new_passwd_file_view, "/etc/passwd"sv));
+
+    auto new_group_file_view = StringView { new_group_file, sizeof(new_group_file) };
+    TRY(Core::System::rename(new_group_file_view, "/etc/group"sv));
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
     auto new_shadow_file_view = StringView { new_shadow_file, sizeof(new_shadow_file) };
     auto new_shadow_file_view = StringView { new_shadow_file, sizeof(new_shadow_file) };
     TRY(Core::System::rename(new_shadow_file_view, "/etc/shadow"sv));
     TRY(Core::System::rename(new_shadow_file_view, "/etc/shadow"sv));
 #endif
 #endif
 
 
     return {};
     return {};
-    // FIXME: Sync extra groups.
 }
 }
 
 
 }
 }

+ 2 - 0
Userland/Libraries/LibCore/Account.h

@@ -53,6 +53,7 @@ public:
     void set_shell(StringView shell) { m_shell = shell; }
     void set_shell(StringView shell) { m_shell = shell; }
     void set_gecos(StringView gecos) { m_gecos = gecos; }
     void set_gecos(StringView gecos) { m_gecos = gecos; }
     void set_deleted() { m_deleted = true; };
     void set_deleted() { m_deleted = true; };
+    void set_extra_gids(Vector<gid_t> extra_gids) { m_extra_gids = move(extra_gids); }
     void delete_password();
     void delete_password();
 
 
     // A null password means that this account was missing from /etc/shadow.
     // A null password means that this account was missing from /etc/shadow.
@@ -74,6 +75,7 @@ private:
     Account(passwd const& pwd, spwd const& spwd, Vector<gid_t> extra_gids);
     Account(passwd const& pwd, spwd const& spwd, Vector<gid_t> extra_gids);
 
 
     ErrorOr<DeprecatedString> generate_passwd_file() const;
     ErrorOr<DeprecatedString> generate_passwd_file() const;
+    ErrorOr<DeprecatedString> generate_group_file() const;
 #ifndef AK_OS_BSD_GENERIC
 #ifndef AK_OS_BSD_GENERIC
     ErrorOr<DeprecatedString> generate_shadow_file() const;
     ErrorOr<DeprecatedString> generate_shadow_file() const;
 #endif
 #endif