summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibCore
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibCore')
-rw-r--r--Userland/Libraries/LibCore/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibCore/Group.cpp103
-rw-r--r--Userland/Libraries/LibCore/Group.h45
3 files changed, 149 insertions, 0 deletions
diff --git a/Userland/Libraries/LibCore/CMakeLists.txt b/Userland/Libraries/LibCore/CMakeLists.txt
index a7eb071d8a..c3eecb178d 100644
--- a/Userland/Libraries/LibCore/CMakeLists.txt
+++ b/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
diff --git a/Userland/Libraries/LibCore/Group.cpp b/Userland/Libraries/LibCore/Group.cpp
new file mode 100644
index 0000000000..586dca33e1
--- /dev/null
+++ b/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;
+}
+
+}
diff --git a/Userland/Libraries/LibCore/Group.h b/Userland/Libraries/LibCore/Group.h
new file mode 100644
index 0000000000..8cd4602984
--- /dev/null
+++ b/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;
+};
+
+}