db-initgroups.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /* Initgroups handling in nss_db module.
  2. Copyright (C) 2011-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. Contributed by Ulrich Drepper <drepper@gmail.com>.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with the GNU C Library; see the file COPYING.LIB. If
  15. not, see <http://www.gnu.org/licenses/>. */
  16. #include <ctype.h>
  17. #include <errno.h>
  18. #include <grp.h>
  19. #include <limits.h>
  20. #include <paths.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <stdint.h>
  24. #include <sys/param.h>
  25. #include "nss_db.h"
  26. /* The hashing function we use. */
  27. #include "../intl/hash-string.h"
  28. enum nss_status
  29. _nss_db_initgroups_dyn (const char *user, gid_t group, long int *start,
  30. long int *size, gid_t **groupsp, long int limit,
  31. int *errnop)
  32. {
  33. struct nss_db_map state = { NULL, 0 };
  34. enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state);
  35. if (status != NSS_STATUS_SUCCESS)
  36. {
  37. *errnop = errno;
  38. return status;
  39. }
  40. const struct nss_db_header *header = state.header;
  41. int i;
  42. for (i = 0; i < header->ndbs; ++i)
  43. if (header->dbs[i].id == ':')
  44. break;
  45. if (i == header->ndbs)
  46. {
  47. status = NSS_STATUS_UNAVAIL;
  48. goto out;
  49. }
  50. const stridx_t *hashtable
  51. = (const stridx_t *) ((const char *) header
  52. + header->dbs[i].hashoffset);
  53. const char *valstrtab = (const char *) header + header->valstroffset;
  54. size_t userlen = strlen (user);
  55. uint32_t hashval = __hash_string (user);
  56. size_t hidx = hashval % header->dbs[i].hashsize;
  57. size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);
  58. gid_t *groups = *groupsp;
  59. status = NSS_STATUS_NOTFOUND;
  60. while (hashtable[hidx] != ~((stridx_t) 0))
  61. {
  62. const char *valstr = valstrtab + hashtable[hidx];
  63. while (isblank (*valstr))
  64. ++valstr;
  65. if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen]))
  66. {
  67. valstr += userlen + 1;
  68. while (isblank (*valstr))
  69. ++valstr;
  70. while (*valstr != '\0')
  71. {
  72. errno = 0;
  73. char *endp;
  74. unsigned long int n = strtoul (valstr, &endp, 10);
  75. if (*endp != ',' && *endp != '\0')
  76. break;
  77. valstr = *endp == '\0' ? endp : endp + 1;
  78. if (n != ULONG_MAX || errno != ERANGE)
  79. {
  80. /* Insert the group. */
  81. if (*start == *size)
  82. {
  83. /* Need a bigger buffer. */
  84. if (limit > 0 && *size == limit)
  85. {
  86. /* We reached the maximum. */
  87. status = NSS_STATUS_SUCCESS;
  88. goto out;
  89. }
  90. long int newsize;
  91. if (limit <= 0)
  92. newsize = 2 * *size;
  93. else
  94. newsize = MIN (limit, 2 * *size);
  95. gid_t *newgroups = realloc (groups,
  96. newsize * sizeof (*groups));
  97. if (newgroups == NULL)
  98. {
  99. *errnop = ENOMEM;
  100. status = NSS_STATUS_TRYAGAIN;
  101. goto out;
  102. }
  103. *groupsp = groups = newgroups;
  104. *size = newsize;
  105. }
  106. groups[*start] = n;
  107. *start += 1;
  108. }
  109. }
  110. status = NSS_STATUS_SUCCESS;
  111. break;
  112. }
  113. if ((hidx += hval2) >= header->dbs[i].hashsize)
  114. hidx -= header->dbs[i].hashsize;
  115. }
  116. out:
  117. internal_endent (&state);
  118. return status;
  119. }