nscd_netgroup.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* Copyright (C) 2011-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 <alloca.h>
  15. #include <errno.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <not-cancel.h>
  19. #include "nscd-client.h"
  20. #include "nscd_proto.h"
  21. int __nss_not_use_nscd_netgroup;
  22. libc_locked_map_ptr (static, map_handle);
  23. /* Note that we only free the structure if necessary. The memory
  24. mapping is not removed since it is not visible to the malloc
  25. handling. */
  26. void
  27. __nscd_group_map_freemem (void)
  28. {
  29. if (map_handle.mapped != NO_MAPPING)
  30. {
  31. void *p = map_handle.mapped;
  32. map_handle.mapped = NO_MAPPING;
  33. free (p);
  34. }
  35. }
  36. int
  37. __nscd_setnetgrent (const char *group, struct __netgrent *datap)
  38. {
  39. int gc_cycle;
  40. int nretries = 0;
  41. size_t group_len = strlen (group) + 1;
  42. /* If the mapping is available, try to search there instead of
  43. communicating with the nscd. */
  44. struct mapped_database *mapped;
  45. mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
  46. retry:;
  47. char *respdata = NULL;
  48. int retval = -1;
  49. netgroup_response_header netgroup_resp;
  50. if (mapped != NO_MAPPING)
  51. {
  52. struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
  53. group_len, mapped,
  54. sizeof netgroup_resp);
  55. if (found != NULL)
  56. {
  57. respdata = (char *) (&found->data[0].netgroupdata + 1);
  58. netgroup_resp = found->data[0].netgroupdata;
  59. /* Now check if we can trust pw_resp fields. If GC is
  60. in progress, it can contain anything. */
  61. if (mapped->head->gc_cycle != gc_cycle)
  62. {
  63. retval = -2;
  64. goto out;
  65. }
  66. }
  67. }
  68. int sock = -1;
  69. if (respdata == NULL)
  70. {
  71. sock = __nscd_open_socket (group, group_len, GETNETGRENT,
  72. &netgroup_resp, sizeof (netgroup_resp));
  73. if (sock == -1)
  74. {
  75. /* nscd not running or wrong version. */
  76. __nss_not_use_nscd_netgroup = 1;
  77. goto out;
  78. }
  79. }
  80. if (netgroup_resp.found == 1)
  81. {
  82. size_t datalen = netgroup_resp.result_len;
  83. /* If we do not have to read the data here it comes from the
  84. mapped data and does not have to be freed. */
  85. if (respdata == NULL)
  86. {
  87. /* The data will come via the socket. */
  88. respdata = malloc (datalen);
  89. if (respdata == NULL)
  90. goto out_close;
  91. if ((size_t) __readall (sock, respdata, datalen) != datalen)
  92. {
  93. free (respdata);
  94. goto out_close;
  95. }
  96. }
  97. datap->data = respdata;
  98. datap->data_size = datalen;
  99. datap->cursor = respdata;
  100. datap->first = 1;
  101. datap->nip = (nss_action_list) -1l;
  102. datap->known_groups = NULL;
  103. datap->needed_groups = NULL;
  104. retval = 1;
  105. }
  106. else
  107. {
  108. if (__glibc_unlikely (netgroup_resp.found == -1))
  109. {
  110. /* The daemon does not cache this database. */
  111. __nss_not_use_nscd_netgroup = 1;
  112. goto out_close;
  113. }
  114. /* Set errno to 0 to indicate no error, just no found record. */
  115. __set_errno (0);
  116. /* Even though we have not found anything, the result is zero. */
  117. retval = 0;
  118. }
  119. out_close:
  120. if (sock != -1)
  121. __close_nocancel_nostatus (sock);
  122. out:
  123. if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
  124. {
  125. /* When we come here this means there has been a GC cycle while we
  126. were looking for the data. This means the data might have been
  127. inconsistent. Retry if possible. */
  128. if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
  129. {
  130. /* nscd is just running gc now. Disable using the mapping. */
  131. if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
  132. __nscd_unmap (mapped);
  133. mapped = NO_MAPPING;
  134. }
  135. if (retval != -1)
  136. goto retry;
  137. }
  138. return retval;
  139. }
  140. int
  141. __nscd_innetgr (const char *netgroup, const char *host, const char *user,
  142. const char *domain)
  143. {
  144. size_t key_len = (strlen (netgroup) + strlen (host ?: "")
  145. + strlen (user ?: "") + strlen (domain ?: "") + 7);
  146. char *key;
  147. bool use_alloca = __libc_use_alloca (key_len);
  148. if (use_alloca)
  149. key = alloca (key_len);
  150. else
  151. {
  152. key = malloc (key_len);
  153. if (key == NULL)
  154. return -1;
  155. }
  156. char *wp = stpcpy (key, netgroup) + 1;
  157. if (host != NULL)
  158. {
  159. *wp++ = '\1';
  160. wp = stpcpy (wp, host) + 1;
  161. }
  162. else
  163. *wp++ = '\0';
  164. if (user != NULL)
  165. {
  166. *wp++ = '\1';
  167. wp = stpcpy (wp, user) + 1;
  168. }
  169. else
  170. *wp++ = '\0';
  171. if (domain != NULL)
  172. {
  173. *wp++ = '\1';
  174. wp = stpcpy (wp, domain) + 1;
  175. }
  176. else
  177. *wp++ = '\0';
  178. key_len = wp - key;
  179. /* If the mapping is available, try to search there instead of
  180. communicating with the nscd. */
  181. int gc_cycle;
  182. int nretries = 0;
  183. struct mapped_database *mapped;
  184. mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
  185. retry:;
  186. int retval = -1;
  187. innetgroup_response_header innetgroup_resp;
  188. int sock = -1;
  189. if (mapped != NO_MAPPING)
  190. {
  191. struct datahead *found = __nscd_cache_search (INNETGR, key,
  192. key_len, mapped,
  193. sizeof innetgroup_resp);
  194. if (found != NULL)
  195. {
  196. innetgroup_resp = found->data[0].innetgroupdata;
  197. /* Now check if we can trust pw_resp fields. If GC is
  198. in progress, it can contain anything. */
  199. if (mapped->head->gc_cycle != gc_cycle)
  200. {
  201. retval = -2;
  202. goto out;
  203. }
  204. goto found_entry;
  205. }
  206. }
  207. sock = __nscd_open_socket (key, key_len, INNETGR,
  208. &innetgroup_resp, sizeof (innetgroup_resp));
  209. if (sock == -1)
  210. {
  211. /* nscd not running or wrong version. */
  212. __nss_not_use_nscd_netgroup = 1;
  213. goto out;
  214. }
  215. found_entry:
  216. if (innetgroup_resp.found == 1)
  217. retval = innetgroup_resp.result;
  218. else
  219. {
  220. if (__glibc_unlikely (innetgroup_resp.found == -1))
  221. {
  222. /* The daemon does not cache this database. */
  223. __nss_not_use_nscd_netgroup = 1;
  224. goto out_close;
  225. }
  226. /* Set errno to 0 to indicate no error, just no found record. */
  227. __set_errno (0);
  228. /* Even though we have not found anything, the result is zero. */
  229. retval = 0;
  230. }
  231. out_close:
  232. if (sock != -1)
  233. __close_nocancel_nostatus (sock);
  234. out:
  235. if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
  236. {
  237. /* When we come here this means there has been a GC cycle while we
  238. were looking for the data. This means the data might have been
  239. inconsistent. Retry if possible. */
  240. if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
  241. {
  242. /* nscd is just running gc now. Disable using the mapping. */
  243. if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1)
  244. __nscd_unmap (mapped);
  245. mapped = NO_MAPPING;
  246. }
  247. if (retval != -1)
  248. goto retry;
  249. }
  250. if (! use_alloca)
  251. free (key);
  252. return retval;
  253. }