浏览代码

LibCore: Add Core::Group abstraction for group management :^)

This adds the Core::Group C++ abstraction to ease interaction with the
group entry database, as well as represent the Group entry.

Core::Group abstraction currently contains the following functionality:
- Add a group entry - 'Core::Group::add_group()'
Kenneth Myhra 3 年之前
父节点
当前提交
a99b50ce8c
共有 3 个文件被更改,包括 149 次插入0 次删除
  1. 1 0
      Userland/Libraries/LibCore/CMakeLists.txt
  2. 103 0
      Userland/Libraries/LibCore/Group.cpp
  3. 45 0
      Userland/Libraries/LibCore/Group.h

+ 1 - 0
Userland/Libraries/LibCore/CMakeLists.txt

@@ -13,6 +13,7 @@ set(SOURCES
     File.cpp
     FilePermissionsMask.cpp
     GetPassword.cpp
+    Group.cpp
     IODevice.cpp
     LocalServer.cpp
     LocalSocket.cpp

+ 103 - 0
Userland/Libraries/LibCore/Group.cpp

@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2022, Kenneth Myhra <kennethmyhra@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/CharacterTypes.h>
+#include <LibCore/Group.h>
+#include <LibCore/System.h>
+
+namespace Core {
+
+#ifndef AK_OS_MACOS
+ErrorOr<void> Group::add_group(Group& group)
+{
+    if (group.name().is_empty())
+        return Error::from_string_literal("Group name can not be empty.");
+
+    // A quick sanity check on group name
+    if (strpbrk(group.name().characters(), "\\/!@#$%^&*()~+=`:\n"))
+        return Error::from_string_literal("Group name has invalid characters.");
+
+    // Disallow names starting with '_', '-' or other non-alpha characters.
+    if (group.name().starts_with('_') || group.name().starts_with('-') || !is_ascii_alpha(group.name().characters()[0]))
+        return Error::from_string_literal("Group name has invalid characters.");
+
+    // Verify group name does not already exist
+    if (TRY(name_exists(group.name())))
+        return Error::from_string_literal("Group name already exists.");
+
+    // Sort out the group id for the group
+    if (group.id() > 0) {
+        if (TRY(id_exists(group.id())))
+            return Error::from_string_literal("Group ID already exists.");
+    } else {
+        gid_t group_id = 100;
+        while (true) {
+            if (!TRY(id_exists(group_id)))
+                break;
+            group_id++;
+        }
+        group.set_group_id(group_id);
+    }
+
+    auto gr = TRY(group.to_libc_group());
+
+    FILE* file = fopen("/etc/group", "a");
+    if (!file)
+        return Error::from_errno(errno);
+
+    if (putgrent(&gr, file) < 0)
+        return Error::from_errno(errno);
+
+    fclose(file);
+
+    return {};
+}
+#endif
+
+Group::Group(String name, gid_t id, Vector<String> members)
+    : m_name(move(name))
+    , m_id(id)
+    , m_members(move(members))
+{
+}
+
+ErrorOr<bool> Group::name_exists(StringView name)
+{
+    return TRY(Core::System::getgrnam(name)).has_value();
+}
+
+ErrorOr<bool> Group::id_exists(gid_t id)
+{
+    return TRY(Core::System::getgrgid(id)).has_value();
+}
+
+// NOTE: struct group returned from this function cannot outlive an instance of Group.
+ErrorOr<struct group> Group::to_libc_group()
+{
+    struct group gr;
+    gr.gr_name = const_cast<char*>(m_name.characters());
+    gr.gr_passwd = const_cast<char*>("x");
+    gr.gr_gid = m_id;
+    gr.gr_mem = nullptr;
+
+    // FIXME: A better solution would surely be not using a static here
+    // NOTE: This now means that there cannot be multiple struct groups at the same time, because only one gr.gr_mem can ever be valid at the same time.
+    // NOTE: Not using a static here would result in gr.gr_mem being freed up on exit from this function.
+    static Vector<char*> members;
+    members.clear_with_capacity();
+    if (m_members.size() > 0) {
+        TRY(members.try_ensure_capacity(m_members.size() + 1));
+        for (auto member : m_members)
+            members.unchecked_append(const_cast<char*>(member.characters()));
+        members.unchecked_append(nullptr);
+
+        gr.gr_mem = const_cast<char**>(members.data());
+    }
+
+    return gr;
+}
+
+}

+ 45 - 0
Userland/Libraries/LibCore/Group.h

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022, Kenneth Myhra <kennethmyhra@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Error.h>
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <grp.h>
+
+namespace Core {
+
+class Group {
+public:
+#ifndef AK_OS_MACOS
+    static ErrorOr<void> add_group(Group& group);
+#endif
+
+    Group() = default;
+    Group(String name, gid_t id = 0, Vector<String> members = {});
+
+    ~Group() = default;
+
+    String const& name() const { return m_name; }
+    void set_name(String const& name) { m_name = name; }
+
+    gid_t id() const { return m_id; }
+    void set_group_id(gid_t const id) { m_id = id; }
+
+    Vector<String>& members() { return m_members; }
+
+private:
+    static ErrorOr<bool> name_exists(StringView name);
+    static ErrorOr<bool> id_exists(gid_t id);
+    ErrorOr<struct group> to_libc_group();
+
+    String m_name;
+    gid_t m_id { 0 };
+    Vector<String> m_members;
+};
+
+}