grp-merge.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* Group merging implementation.
  2. Copyright (C) 2016-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <errno.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <grp.h>
  19. #include <grp-merge.h>
  20. #define BUFCHECK(size) \
  21. ({ \
  22. do \
  23. { \
  24. if (c + (size) > buflen) \
  25. { \
  26. free (members); \
  27. return ERANGE; \
  28. } \
  29. } \
  30. while (0); \
  31. })
  32. int
  33. __copy_grp (const struct group srcgrp, const size_t buflen,
  34. struct group *destgrp, char *destbuf, char **endptr)
  35. {
  36. size_t i;
  37. size_t c = 0;
  38. size_t len;
  39. size_t memcount;
  40. char **members = NULL;
  41. /* Copy the GID. */
  42. destgrp->gr_gid = srcgrp.gr_gid;
  43. /* Copy the name. */
  44. len = strlen (srcgrp.gr_name) + 1;
  45. BUFCHECK (len);
  46. memcpy (&destbuf[c], srcgrp.gr_name, len);
  47. destgrp->gr_name = &destbuf[c];
  48. c += len;
  49. /* Copy the password. */
  50. len = strlen (srcgrp.gr_passwd) + 1;
  51. BUFCHECK (len);
  52. memcpy (&destbuf[c], srcgrp.gr_passwd, len);
  53. destgrp->gr_passwd = &destbuf[c];
  54. c += len;
  55. /* Count all of the members. */
  56. for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
  57. ;
  58. /* Allocate a temporary holding area for the pointers to the member
  59. contents, including space for a NULL-terminator. */
  60. members = malloc (sizeof (char *) * (memcount + 1));
  61. if (members == NULL)
  62. return ENOMEM;
  63. /* Copy all of the group members to destbuf and add a pointer to each of
  64. them into the 'members' array. */
  65. for (i = 0; srcgrp.gr_mem[i]; i++)
  66. {
  67. len = strlen (srcgrp.gr_mem[i]) + 1;
  68. BUFCHECK (len);
  69. memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
  70. members[i] = &destbuf[c];
  71. c += len;
  72. }
  73. members[i] = NULL;
  74. /* Align for pointers. We can't simply align C because we need to
  75. align destbuf[c]. */
  76. if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
  77. {
  78. uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
  79. c += __alignof__(char **) - mis_align;
  80. }
  81. /* Copy the pointers from the members array into the buffer and assign them
  82. to the gr_mem member of destgrp. */
  83. destgrp->gr_mem = (char **) &destbuf[c];
  84. len = sizeof (char *) * (memcount + 1);
  85. BUFCHECK (len);
  86. memcpy (&destbuf[c], members, len);
  87. c += len;
  88. free (members);
  89. members = NULL;
  90. /* Save the count of members at the end. */
  91. BUFCHECK (sizeof (size_t));
  92. memcpy (&destbuf[c], &memcount, sizeof (size_t));
  93. c += sizeof (size_t);
  94. if (endptr)
  95. *endptr = destbuf + c;
  96. return 0;
  97. }
  98. libc_hidden_def (__copy_grp)
  99. /* Check that the name, GID and passwd fields match, then
  100. copy in the gr_mem array. */
  101. int
  102. __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
  103. size_t buflen, struct group *mergegrp, char *mergebuf)
  104. {
  105. size_t c, i, len;
  106. size_t savedmemcount;
  107. size_t memcount;
  108. size_t membersize;
  109. char **members = NULL;
  110. /* We only support merging members of groups with identical names and
  111. GID values. If we hit this case, we need to overwrite the current
  112. buffer with the saved one (which is functionally equivalent to
  113. treating the new lookup as NSS_STATUS_NOTFOUND). */
  114. if (mergegrp->gr_gid != savedgrp->gr_gid
  115. || strcmp (mergegrp->gr_name, savedgrp->gr_name))
  116. return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
  117. /* Get the count of group members from the last sizeof (size_t) bytes in the
  118. mergegrp buffer. */
  119. savedmemcount = *(size_t *) (savedend - sizeof (size_t));
  120. /* Get the count of new members to add. */
  121. for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
  122. ;
  123. /* Create a temporary array to hold the pointers to the member values from
  124. both the saved and merge groups. */
  125. membersize = savedmemcount + memcount + 1;
  126. members = malloc (sizeof (char *) * membersize);
  127. if (members == NULL)
  128. return ENOMEM;
  129. /* Copy in the existing member pointers from the saved group
  130. Note: this is not NULL-terminated yet. */
  131. memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
  132. /* Back up into the savedbuf until we get back to the NULL-terminator of the
  133. group member list. (This means walking back savedmemcount + 1 (char *) pointers
  134. and the member count value.
  135. The value of c is going to be the used length of the buffer backed up by
  136. the member count and further backed up by the size of the pointers. */
  137. c = savedend - savedbuf
  138. - sizeof (size_t)
  139. - sizeof (char *) * (savedmemcount + 1);
  140. /* Add all the new group members, overwriting the old NULL-terminator while
  141. adding the new pointers to the temporary array. */
  142. for (i = 0; mergegrp->gr_mem[i]; i++)
  143. {
  144. len = strlen (mergegrp->gr_mem[i]) + 1;
  145. BUFCHECK (len);
  146. memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
  147. members[savedmemcount + i] = &savedbuf[c];
  148. c += len;
  149. }
  150. /* Add the NULL-terminator. */
  151. members[savedmemcount + memcount] = NULL;
  152. /* Align for pointers. We can't simply align C because we need to
  153. align savedbuf[c]. */
  154. if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
  155. {
  156. uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
  157. c += __alignof__(char **) - mis_align;
  158. }
  159. /* Copy the member array back into the buffer after the member list and free
  160. the member array. */
  161. savedgrp->gr_mem = (char **) &savedbuf[c];
  162. len = sizeof (char *) * membersize;
  163. BUFCHECK (len);
  164. memcpy (&savedbuf[c], members, len);
  165. c += len;
  166. free (members);
  167. members = NULL;
  168. /* Finally, copy the results back into mergebuf, since that's the buffer
  169. that we were provided by the caller. */
  170. return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
  171. }
  172. libc_hidden_def (__merge_grp)