grp.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/String.h>
  7. #include <AK/Vector.h>
  8. #include <errno_numbers.h>
  9. #include <grp.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. extern "C" {
  15. static FILE* s_stream = nullptr;
  16. static unsigned s_line_number = 0;
  17. static struct group s_group;
  18. static String s_name;
  19. static String s_passwd;
  20. static Vector<String> s_members;
  21. static Vector<const char*> s_members_ptrs;
  22. void setgrent()
  23. {
  24. s_line_number = 0;
  25. if (s_stream) {
  26. rewind(s_stream);
  27. } else {
  28. s_stream = fopen("/etc/group", "r");
  29. if (!s_stream) {
  30. perror("open /etc/group");
  31. }
  32. }
  33. }
  34. void endgrent()
  35. {
  36. s_line_number = 0;
  37. if (s_stream) {
  38. fclose(s_stream);
  39. s_stream = nullptr;
  40. }
  41. memset(&s_group, 0, sizeof(s_group));
  42. s_name = {};
  43. s_passwd = {};
  44. s_members = {};
  45. s_members_ptrs = {};
  46. }
  47. struct group* getgrgid(gid_t gid)
  48. {
  49. setgrent();
  50. while (auto* gr = getgrent()) {
  51. if (gr->gr_gid == gid)
  52. return gr;
  53. }
  54. return nullptr;
  55. }
  56. struct group* getgrnam(const char* name)
  57. {
  58. setgrent();
  59. while (auto* gr = getgrent()) {
  60. if (!strcmp(gr->gr_name, name))
  61. return gr;
  62. }
  63. return nullptr;
  64. }
  65. static bool parse_grpdb_entry(const String& line)
  66. {
  67. auto parts = line.split_view(':', true);
  68. if (parts.size() != 4) {
  69. warnln("getgrent(): Malformed entry on line {}: '{}' has {} parts", s_line_number, line, parts.size());
  70. return false;
  71. }
  72. s_name = parts[0];
  73. s_passwd = parts[1];
  74. auto& gid_string = parts[2];
  75. String members_string = parts[3];
  76. auto gid = gid_string.to_uint();
  77. if (!gid.has_value()) {
  78. warnln("getgrent(): Malformed GID on line {}", s_line_number);
  79. return false;
  80. }
  81. s_members = members_string.split(',');
  82. s_members_ptrs.clear_with_capacity();
  83. s_members_ptrs.ensure_capacity(s_members.size() + 1);
  84. for (auto& member : s_members) {
  85. s_members_ptrs.append(member.characters());
  86. }
  87. s_members_ptrs.append(nullptr);
  88. s_group.gr_gid = gid.value();
  89. s_group.gr_name = const_cast<char*>(s_name.characters());
  90. s_group.gr_passwd = const_cast<char*>(s_passwd.characters());
  91. s_group.gr_mem = const_cast<char**>(s_members_ptrs.data());
  92. return true;
  93. }
  94. struct group* getgrent()
  95. {
  96. if (!s_stream)
  97. setgrent();
  98. while (true) {
  99. if (!s_stream || feof(s_stream))
  100. return nullptr;
  101. if (ferror(s_stream)) {
  102. warnln("getgrent(): Read error: {}", strerror(ferror(s_stream)));
  103. return nullptr;
  104. }
  105. char buffer[1024];
  106. ++s_line_number;
  107. char* s = fgets(buffer, sizeof(buffer), s_stream);
  108. // Silently tolerate an empty line at the end.
  109. if ((!s || !s[0]) && feof(s_stream))
  110. return nullptr;
  111. String line(s, Chomp);
  112. if (parse_grpdb_entry(line))
  113. return &s_group;
  114. // Otherwise, proceed to the next line.
  115. }
  116. }
  117. int initgroups(const char* user, gid_t extra_gid)
  118. {
  119. size_t count = 0;
  120. gid_t gids[32];
  121. bool extra_gid_added = false;
  122. setgrent();
  123. while (auto* gr = getgrent()) {
  124. for (auto* mem = gr->gr_mem; *mem; ++mem) {
  125. if (!strcmp(*mem, user)) {
  126. gids[count++] = gr->gr_gid;
  127. if (gr->gr_gid == extra_gid)
  128. extra_gid_added = true;
  129. break;
  130. }
  131. }
  132. }
  133. endgrent();
  134. if (!extra_gid_added)
  135. gids[count++] = extra_gid;
  136. return setgroups(count, gids);
  137. }
  138. }