summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibCore/Group.cpp
diff options
context:
space:
mode:
authorKenneth Myhra <kennethmyhra@gmail.com>2022-01-02 22:41:29 +0100
committerAndreas Kling <kling@serenityos.org>2022-01-16 11:19:07 +0100
commita99b50ce8c790e0ba394ef7ed580bfc414f4af4c (patch)
tree6f369a3e67827d4e549e4967804bbbdafa45da83 /Userland/Libraries/LibCore/Group.cpp
parentadfdb63e0207afdb43a9d7e505502ee544ce7ab5 (diff)
downloadserenity-a99b50ce8c790e0ba394ef7ed580bfc414f4af4c.zip
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()'
Diffstat (limited to 'Userland/Libraries/LibCore/Group.cpp')
-rw-r--r--Userland/Libraries/LibCore/Group.cpp103
1 files changed, 103 insertions, 0 deletions
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;
+}
+
+}