grp.cpp 4.7 KB

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