initgroups.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /* Copyright (C) 1989, 1991-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>. */
  14. #include <assert.h>
  15. #include <errno.h>
  16. #include <grp.h>
  17. #include <limits.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <sys/param.h>
  22. #include <sys/types.h>
  23. #include <nsswitch.h>
  24. #include <scratch_buffer.h>
  25. #include <config.h>
  26. #include "../nscd/nscd-client.h"
  27. #include "../nscd/nscd_proto.h"
  28. /* Type of the lookup function. */
  29. typedef enum nss_status (*initgroups_dyn_function) (const char *, gid_t,
  30. long int *, long int *,
  31. gid_t **, long int, int *);
  32. static bool use_initgroups_entry;
  33. #include "initgroups-fallback.c"
  34. static int
  35. internal_getgrouplist (const char *user, gid_t group, long int *size,
  36. gid_t **groupsp, long int limit)
  37. {
  38. #ifdef USE_NSCD
  39. if (__nss_not_use_nscd_group > 0
  40. && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
  41. __nss_not_use_nscd_group = 0;
  42. if (!__nss_not_use_nscd_group
  43. && !__nss_database_custom[NSS_DBSIDX_group])
  44. {
  45. int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
  46. if (n >= 0)
  47. return n;
  48. /* nscd is not usable. */
  49. __nss_not_use_nscd_group = 1;
  50. }
  51. #endif
  52. enum nss_status status = NSS_STATUS_UNAVAIL;
  53. /* Never store more than the starting *SIZE number of elements. */
  54. assert (*size > 0);
  55. (*groupsp)[0] = group;
  56. /* Start is one, because we have the first group as parameter. */
  57. long int start = 1;
  58. nss_action_list nip;
  59. if (__nss_database_get (nss_database_initgroups, &nip)
  60. && nip != NULL)
  61. {
  62. use_initgroups_entry = true;
  63. }
  64. else if (__nss_database_get (nss_database_group, &nip)
  65. && nip != NULL)
  66. {
  67. use_initgroups_entry = false;
  68. }
  69. else
  70. {
  71. nip = __nss_action_parse ("files");
  72. use_initgroups_entry = false;
  73. }
  74. while (nip && nip->module)
  75. {
  76. long int prev_start = start;
  77. initgroups_dyn_function fct = __nss_lookup_function (nip,
  78. "initgroups_dyn");
  79. if (fct == NULL)
  80. status = compat_call (nip, user, group, &start, size, groupsp,
  81. limit, &errno);
  82. else
  83. status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
  84. limit, &errno));
  85. /* Remove duplicates. */
  86. long int cnt = prev_start;
  87. while (cnt < start)
  88. {
  89. long int inner;
  90. for (inner = 0; inner < prev_start; ++inner)
  91. if ((*groupsp)[inner] == (*groupsp)[cnt])
  92. break;
  93. if (inner < prev_start)
  94. (*groupsp)[cnt] = (*groupsp)[--start];
  95. else
  96. ++cnt;
  97. }
  98. /* This is really only for debugging. */
  99. if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
  100. __libc_fatal ("Illegal status in internal_getgrouplist.\n");
  101. /* For compatibility reason we will continue to look for more
  102. entries using the next service even though data has already
  103. been found if the nsswitch.conf file contained only a 'groups'
  104. line and no 'initgroups' line. If the latter is available
  105. we always respect the status. This means that the default
  106. for successful lookups is to return. */
  107. if ((use_initgroups_entry || status != NSS_STATUS_SUCCESS)
  108. && nss_next_action (nip, status) == NSS_ACTION_RETURN)
  109. break;
  110. nip++;
  111. }
  112. return start;
  113. }
  114. /* Store at most *NGROUPS members of the group set for USER into
  115. *GROUPS. Also include GROUP. The actual number of groups found is
  116. returned in *NGROUPS. Return -1 if the if *NGROUPS is too small. */
  117. int
  118. getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
  119. {
  120. long int size = MAX (1, *ngroups);
  121. gid_t *newgroups = (gid_t *) malloc (size * sizeof (gid_t));
  122. if (__glibc_unlikely (newgroups == NULL))
  123. /* No more memory. */
  124. // XXX This is wrong. The user provided memory, we have to use
  125. // XXX it. The internal functions must be called with the user
  126. // XXX provided buffer and not try to increase the size if it is
  127. // XXX too small. For initgroups a flag could say: increase size.
  128. return -1;
  129. int total = internal_getgrouplist (user, group, &size, &newgroups, -1);
  130. memcpy (groups, newgroups, MIN (*ngroups, total) * sizeof (gid_t));
  131. free (newgroups);
  132. int retval = total > *ngroups ? -1 : total;
  133. *ngroups = total;
  134. return retval;
  135. }
  136. nss_interface_function (getgrouplist)
  137. /* Initialize the group set for the current user
  138. by reading the group database and using all groups
  139. of which USER is a member. Also include GROUP. */
  140. int
  141. initgroups (const char *user, gid_t group)
  142. {
  143. #if defined NGROUPS_MAX && NGROUPS_MAX == 0
  144. /* No extra groups allowed. */
  145. return 0;
  146. #else
  147. long int size;
  148. gid_t *groups;
  149. int ngroups;
  150. int result;
  151. /* We always use sysconf even if NGROUPS_MAX is defined. That way, the
  152. limit can be raised in the kernel configuration without having to
  153. recompile libc. */
  154. long int limit = __sysconf (_SC_NGROUPS_MAX);
  155. if (limit > 0)
  156. /* We limit the size of the initially allocated array. */
  157. size = MIN (limit, 64);
  158. else
  159. /* No fixed limit on groups. Pick a starting buffer size. */
  160. size = 16;
  161. groups = (gid_t *) malloc (size * sizeof (gid_t));
  162. if (__glibc_unlikely (groups == NULL))
  163. /* No more memory. */
  164. return -1;
  165. ngroups = internal_getgrouplist (user, group, &size, &groups, limit);
  166. /* Try to set the maximum number of groups the kernel can handle. */
  167. do
  168. result = setgroups (ngroups, groups);
  169. while (result == -1 && errno == EINVAL && --ngroups > 0);
  170. free (groups);
  171. return result;
  172. #endif
  173. }
  174. nss_interface_function (initgroups)