grp.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include <grp.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/mman.h>
  6. #include <AK/AKString.h>
  7. extern "C" {
  8. #define GRDB_STR_MAX_LEN 256
  9. struct group_with_strings : public group {
  10. char name_buffer[GRDB_STR_MAX_LEN];
  11. char passwd_buffer[GRDB_STR_MAX_LEN];
  12. char* members[32];
  13. char members_buffer[32][32];
  14. };
  15. static FILE* __grdb_stream = nullptr;
  16. static unsigned __grdb_line_number = 0;
  17. static struct group_with_strings* __grdb_entry = nullptr;
  18. void setgrent()
  19. {
  20. __grdb_line_number = 0;
  21. if (__grdb_stream) {
  22. rewind(__grdb_stream);
  23. } else {
  24. __grdb_stream = fopen("/etc/group", "r");
  25. if (!__grdb_stream) {
  26. perror("open /etc/group");
  27. }
  28. assert(__grdb_stream);
  29. __grdb_entry = (struct group_with_strings*)mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  30. set_mmap_name(__grdb_entry, getpagesize(), "setgrent");
  31. }
  32. }
  33. void endgrent()
  34. {
  35. __grdb_line_number = 0;
  36. if (__grdb_stream) {
  37. fclose(__grdb_stream);
  38. __grdb_stream = nullptr;
  39. }
  40. if (__grdb_entry) {
  41. munmap(__grdb_entry, getpagesize());
  42. __grdb_entry = nullptr;
  43. }
  44. }
  45. struct group* getgrgid(gid_t gid)
  46. {
  47. setgrent();
  48. while (auto* gr = getgrent()) {
  49. if (gr->gr_gid == gid)
  50. return gr;
  51. }
  52. return nullptr;
  53. }
  54. struct group* getgrname(const char* name)
  55. {
  56. setgrent();
  57. while (auto* gr = getgrent()) {
  58. if (!strcmp(gr->gr_name, name))
  59. return gr;
  60. }
  61. return nullptr;
  62. }
  63. struct group* getgrent()
  64. {
  65. if (!__grdb_stream)
  66. setgrent();
  67. assert(__grdb_stream);
  68. if (feof(__grdb_stream))
  69. return nullptr;
  70. next_entry:
  71. char buffer[1024];
  72. ++__grdb_line_number;
  73. char* s = fgets(buffer, sizeof(buffer), __grdb_stream);
  74. if (!s)
  75. return nullptr;
  76. assert(__grdb_stream);
  77. if (feof(__grdb_stream))
  78. return nullptr;
  79. String line(s, Chomp);
  80. auto parts = line.split(':');
  81. if (parts.size() != 4) {
  82. fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %u parts\n", __grdb_line_number, line.characters(), parts.size());
  83. goto next_entry;
  84. }
  85. auto& e_name = parts[0];
  86. auto& e_passwd = parts[1];
  87. auto& e_gid_string = parts[2];
  88. auto& e_members_string = parts[3];
  89. bool ok;
  90. gid_t e_gid = e_gid_string.to_uint(ok);
  91. if (!ok) {
  92. fprintf(stderr, "getgrent(): Malformed GID on line %u\n", __grdb_line_number);
  93. goto next_entry;
  94. }
  95. auto members = e_members_string.split(',');
  96. __grdb_entry->gr_gid = e_gid;
  97. __grdb_entry->gr_name = __grdb_entry->name_buffer;
  98. __grdb_entry->gr_passwd = __grdb_entry->passwd_buffer;
  99. for (size_t i = 0; i < members.size(); ++i) {
  100. __grdb_entry->members[i] = __grdb_entry->members_buffer[i];
  101. strcpy(__grdb_entry->members_buffer[i], members[i].characters());
  102. }
  103. __grdb_entry->members[members.size()] = nullptr;
  104. __grdb_entry->gr_mem = __grdb_entry->members;
  105. strncpy(__grdb_entry->name_buffer, e_name.characters(), GRDB_STR_MAX_LEN);
  106. strncpy(__grdb_entry->passwd_buffer, e_passwd.characters(), GRDB_STR_MAX_LEN);
  107. return __grdb_entry;
  108. }
  109. int initgroups(const char* user, gid_t extra_gid)
  110. {
  111. size_t count = 0;
  112. gid_t gids[32];
  113. bool extra_gid_added = false;
  114. setgrent();
  115. while (auto* gr = getgrent()) {
  116. for (auto* mem = gr->gr_mem; *mem; ++mem) {
  117. if (!strcmp(*mem, user)) {
  118. gids[count++] = gr->gr_gid;
  119. if (gr->gr_gid == extra_gid)
  120. extra_gid_added = true;
  121. break;
  122. }
  123. }
  124. }
  125. endgrent();
  126. if (!extra_gid_added)
  127. gids[count++] = extra_gid;
  128. return setgroups(count, gids);
  129. }
  130. }