Group.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright (c) 2022, Kenneth Myhra <kennethmyhra@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/CharacterTypes.h>
  7. #include <AK/ScopeGuard.h>
  8. #include <LibCore/File.h>
  9. #include <LibCore/Group.h>
  10. #include <LibCore/System.h>
  11. #include <errno.h>
  12. namespace Core {
  13. #if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID)
  14. ErrorOr<void> Group::add_group(Group& group)
  15. {
  16. if (group.name().is_empty())
  17. return Error::from_string_literal("Group name can not be empty.");
  18. // A quick sanity check on group name
  19. if (strpbrk(group.name().characters(), "\\/!@#$%^&*()~+=`:\n"))
  20. return Error::from_string_literal("Group name has invalid characters.");
  21. // Disallow names starting with '_', '-' or other non-alpha characters.
  22. if (group.name().starts_with('_') || group.name().starts_with('-') || !is_ascii_alpha(group.name().characters()[0]))
  23. return Error::from_string_literal("Group name has invalid characters.");
  24. // Verify group name does not already exist
  25. if (TRY(name_exists(group.name())))
  26. return Error::from_string_literal("Group name already exists.");
  27. // Sort out the group id for the group
  28. if (group.id() > 0) {
  29. if (TRY(id_exists(group.id())))
  30. return Error::from_string_literal("Group ID already exists.");
  31. } else {
  32. gid_t group_id = 100;
  33. while (true) {
  34. if (!TRY(id_exists(group_id)))
  35. break;
  36. group_id++;
  37. }
  38. group.set_group_id(group_id);
  39. }
  40. auto gr = TRY(group.to_libc_group());
  41. FILE* file = fopen("/etc/group", "a");
  42. if (!file)
  43. return Error::from_errno(errno);
  44. ScopeGuard file_guard { [&] {
  45. fclose(file);
  46. } };
  47. if (putgrent(&gr, file) < 0)
  48. return Error::from_errno(errno);
  49. return {};
  50. }
  51. #endif
  52. ErrorOr<Vector<Group>> Group::all()
  53. {
  54. Vector<Group> groups;
  55. ScopeGuard grent_guard([] { endgrent(); });
  56. setgrent();
  57. errno = 0;
  58. for (auto const* gr = getgrent(); gr; gr = getgrent()) {
  59. Vector<String> members;
  60. for (size_t i = 0; gr->gr_mem[i]; ++i)
  61. members.append(*gr->gr_mem);
  62. groups.append({ gr->gr_name, gr->gr_gid, members });
  63. }
  64. if (errno)
  65. return Error::from_errno(errno);
  66. return groups;
  67. }
  68. Group::Group(String name, gid_t id, Vector<String> members)
  69. : m_name(move(name))
  70. , m_id(id)
  71. , m_members(move(members))
  72. {
  73. }
  74. ErrorOr<bool> Group::name_exists(StringView name)
  75. {
  76. return TRY(Core::System::getgrnam(name)).has_value();
  77. }
  78. ErrorOr<bool> Group::id_exists(gid_t id)
  79. {
  80. return TRY(Core::System::getgrgid(id)).has_value();
  81. }
  82. // NOTE: struct group returned from this function cannot outlive an instance of Group.
  83. ErrorOr<struct group> Group::to_libc_group()
  84. {
  85. struct group gr;
  86. gr.gr_name = const_cast<char*>(m_name.characters());
  87. gr.gr_passwd = const_cast<char*>("x");
  88. gr.gr_gid = m_id;
  89. gr.gr_mem = nullptr;
  90. // FIXME: A better solution would surely be not using a static here
  91. // 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.
  92. // NOTE: Not using a static here would result in gr.gr_mem being freed up on exit from this function.
  93. static Vector<char*> members;
  94. members.clear_with_capacity();
  95. if (m_members.size() > 0) {
  96. TRY(members.try_ensure_capacity(m_members.size() + 1));
  97. for (auto member : m_members)
  98. members.unchecked_append(const_cast<char*>(member.characters()));
  99. members.unchecked_append(nullptr);
  100. gr.gr_mem = const_cast<char**>(members.data());
  101. }
  102. return gr;
  103. }
  104. }