PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/nscd/nscd_getpw_r.c

https://gitlab.com/Namal/glibc
C | 241 lines | 171 code | 28 blank | 42 comment | 49 complexity | c3824b6c90bdd3dcb84b1ebca04b1b87 MD5 | raw file
  1. /* Copyright (C) 1998-2016 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
  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 <assert.h>
  16. #include <errno.h>
  17. #include <pwd.h>
  18. #include <stdint.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <sys/mman.h>
  24. #include <sys/socket.h>
  25. #include <sys/uio.h>
  26. #include <sys/un.h>
  27. #include <not-cancel.h>
  28. #include <_itoa.h>
  29. #include "nscd-client.h"
  30. #include "nscd_proto.h"
  31. int __nss_not_use_nscd_passwd;
  32. static int nscd_getpw_r (const char *key, size_t keylen, request_type type,
  33. struct passwd *resultbuf, char *buffer,
  34. size_t buflen, struct passwd **result)
  35. internal_function;
  36. int
  37. __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
  38. size_t buflen, struct passwd **result)
  39. {
  40. if (name == NULL)
  41. return -1;
  42. return nscd_getpw_r (name, strlen (name) + 1, GETPWBYNAME, resultbuf,
  43. buffer, buflen, result);
  44. }
  45. int
  46. __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
  47. size_t buflen, struct passwd **result)
  48. {
  49. char buf[3 * sizeof (uid_t)];
  50. buf[sizeof (buf) - 1] = '\0';
  51. char *cp = _itoa_word (uid, buf + sizeof (buf) - 1, 10, 0);
  52. return nscd_getpw_r (cp, buf + sizeof (buf) - cp, GETPWBYUID, resultbuf,
  53. buffer, buflen, result);
  54. }
  55. libc_locked_map_ptr (static, map_handle);
  56. /* Note that we only free the structure if necessary. The memory
  57. mapping is not removed since it is not visible to the malloc
  58. handling. */
  59. libc_freeres_fn (pw_map_free)
  60. {
  61. if (map_handle.mapped != NO_MAPPING)
  62. {
  63. void *p = map_handle.mapped;
  64. map_handle.mapped = NO_MAPPING;
  65. free (p);
  66. }
  67. }
  68. static int
  69. internal_function
  70. nscd_getpw_r (const char *key, size_t keylen, request_type type,
  71. struct passwd *resultbuf, char *buffer, size_t buflen,
  72. struct passwd **result)
  73. {
  74. int gc_cycle;
  75. int nretries = 0;
  76. /* If the mapping is available, try to search there instead of
  77. communicating with the nscd. */
  78. struct mapped_database *mapped;
  79. mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
  80. retry:;
  81. const char *pw_name = NULL;
  82. int retval = -1;
  83. const char *recend = (const char *) ~UINTMAX_C (0);
  84. pw_response_header pw_resp;
  85. if (mapped != NO_MAPPING)
  86. {
  87. struct datahead *found = __nscd_cache_search (type, key, keylen, mapped,
  88. sizeof pw_resp);
  89. if (found != NULL)
  90. {
  91. pw_name = (const char *) (&found->data[0].pwdata + 1);
  92. pw_resp = found->data[0].pwdata;
  93. recend = (const char *) found->data + found->recsize;
  94. /* Now check if we can trust pw_resp fields. If GC is
  95. in progress, it can contain anything. */
  96. if (mapped->head->gc_cycle != gc_cycle)
  97. {
  98. retval = -2;
  99. goto out;
  100. }
  101. }
  102. }
  103. int sock = -1;
  104. if (pw_name == NULL)
  105. {
  106. sock = __nscd_open_socket (key, keylen, type, &pw_resp,
  107. sizeof (pw_resp));
  108. if (sock == -1)
  109. {
  110. __nss_not_use_nscd_passwd = 1;
  111. goto out;
  112. }
  113. }
  114. /* No value found so far. */
  115. *result = NULL;
  116. if (__glibc_unlikely (pw_resp.found == -1))
  117. {
  118. /* The daemon does not cache this database. */
  119. __nss_not_use_nscd_passwd = 1;
  120. goto out_close;
  121. }
  122. if (pw_resp.found == 1)
  123. {
  124. /* Set the information we already have. */
  125. resultbuf->pw_uid = pw_resp.pw_uid;
  126. resultbuf->pw_gid = pw_resp.pw_gid;
  127. char *p = buffer;
  128. /* get pw_name */
  129. resultbuf->pw_name = p;
  130. p += pw_resp.pw_name_len;
  131. /* get pw_passwd */
  132. resultbuf->pw_passwd = p;
  133. p += pw_resp.pw_passwd_len;
  134. /* get pw_gecos */
  135. resultbuf->pw_gecos = p;
  136. p += pw_resp.pw_gecos_len;
  137. /* get pw_dir */
  138. resultbuf->pw_dir = p;
  139. p += pw_resp.pw_dir_len;
  140. /* get pw_pshell */
  141. resultbuf->pw_shell = p;
  142. p += pw_resp.pw_shell_len;
  143. ssize_t total = p - buffer;
  144. if (__glibc_unlikely (pw_name + total > recend))
  145. goto out_close;
  146. if (__glibc_unlikely (buflen < total))
  147. {
  148. __set_errno (ERANGE);
  149. retval = ERANGE;
  150. goto out_close;
  151. }
  152. retval = 0;
  153. if (pw_name == NULL)
  154. {
  155. ssize_t nbytes = __readall (sock, buffer, total);
  156. if (__glibc_unlikely (nbytes != total))
  157. {
  158. /* The `errno' to some value != ERANGE. */
  159. __set_errno (ENOENT);
  160. retval = ENOENT;
  161. }
  162. else
  163. *result = resultbuf;
  164. }
  165. else
  166. {
  167. /* Copy the various strings. */
  168. memcpy (resultbuf->pw_name, pw_name, total);
  169. /* Try to detect corrupt databases. */
  170. if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0'
  171. || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0'
  172. || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0'
  173. || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0'
  174. || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
  175. {
  176. /* We cannot use the database. */
  177. retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
  178. goto out_close;
  179. }
  180. *result = resultbuf;
  181. }
  182. }
  183. else
  184. {
  185. /* Set errno to 0 to indicate no error, just no found record. */
  186. __set_errno (0);
  187. /* Even though we have not found anything, the result is zero. */
  188. retval = 0;
  189. }
  190. out_close:
  191. if (sock != -1)
  192. close_not_cancel_no_status (sock);
  193. out:
  194. if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
  195. {
  196. /* When we come here this means there has been a GC cycle while we
  197. were looking for the data. This means the data might have been
  198. inconsistent. Retry if possible. */
  199. if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
  200. {
  201. /* nscd is just running gc now. Disable using the mapping. */
  202. if (atomic_decrement_val (&mapped->counter) == 0)
  203. __nscd_unmap (mapped);
  204. mapped = NO_MAPPING;
  205. }
  206. if (retval != -1)
  207. goto retry;
  208. }
  209. return retval;
  210. }