db-XXX.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /* Common code for DB-based databases in nss_db module.
  2. Copyright (C) 1996-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 <dlfcn.h>
  16. #include <fcntl.h>
  17. #include <stdint.h>
  18. #include <sys/mman.h>
  19. #include <libc-lock.h>
  20. #include "nsswitch.h"
  21. #include "nss_db.h"
  22. /* The hashing function we use. */
  23. #include "../intl/hash-string.h"
  24. /* These symbols are defined by the including source file:
  25. ENTNAME -- database name of the structure and functions (hostent, pwent).
  26. STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
  27. DATABASE -- database file name, ("hosts", "passwd")
  28. NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
  29. */
  30. #define ENTNAME_r CONCAT(ENTNAME,_r)
  31. #include <paths.h>
  32. #define DBFILE _PATH_VARDB DATABASE ".db"
  33. #ifdef NEED_H_ERRNO
  34. # define H_ERRNO_PROTO , int *herrnop
  35. # define H_ERRNO_ARG , herrnop
  36. # define H_ERRNO_SET(val) (*herrnop = (val))
  37. #else
  38. # define H_ERRNO_PROTO
  39. # define H_ERRNO_ARG
  40. # define H_ERRNO_SET(val) ((void) 0)
  41. #endif
  42. /* State for this database. */
  43. static struct nss_db_map state;
  44. /* Lock to protect the state and global variables. */
  45. __libc_lock_define (static , lock);
  46. /* Maintenance of the shared handle open on the database. */
  47. static int keep_db;
  48. static const char *entidx;
  49. /* Open the database. */
  50. enum nss_status
  51. CONCAT(_nss_db_set,ENTNAME) (int stayopen)
  52. {
  53. enum nss_status status;
  54. __libc_lock_lock (lock);
  55. status = internal_setent (DBFILE, &state);
  56. if (status == NSS_STATUS_SUCCESS)
  57. {
  58. /* Remember STAYOPEN flag. */
  59. keep_db |= stayopen;
  60. /* Reset the sequential index. */
  61. entidx = NULL;
  62. }
  63. __libc_lock_unlock (lock);
  64. return status;
  65. }
  66. /* Close it again. */
  67. enum nss_status
  68. CONCAT(_nss_db_end,ENTNAME) (void)
  69. {
  70. __libc_lock_lock (lock);
  71. internal_endent (&state);
  72. /* Reset STAYOPEN flag. */
  73. keep_db = 0;
  74. __libc_lock_unlock (lock);
  75. return NSS_STATUS_SUCCESS;
  76. }
  77. /* Macro for defining lookup functions for this DB-based database.
  78. NAME is the name of the lookup; e.g. `pwnam'.
  79. DB_CHAR is index indicator for the database.
  80. KEYPATTERN gives `printf' args to construct a key string;
  81. e.g. `("%d", id)'.
  82. KEYSIZE gives the allocation size of a buffer to construct it in;
  83. e.g. `1 + sizeof (id) * 4'.
  84. PROTO is the potentially empty list of other parameters.
  85. BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
  86. to the lookup key arguments and does `break;' if they match. */
  87. #define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
  88. enum nss_status \
  89. _nss_db_get##name##_r (proto, struct STRUCTURE *result, \
  90. char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\
  91. { \
  92. struct parser_data *data = (void *) buffer; \
  93. \
  94. if (buflen < sizeof *data) \
  95. { \
  96. *errnop = ERANGE; \
  97. H_ERRNO_SET (NETDB_INTERNAL); \
  98. return NSS_STATUS_TRYAGAIN; \
  99. } \
  100. \
  101. struct nss_db_map state = { NULL, 0 }; \
  102. enum nss_status status = internal_setent (DBFILE, &state); \
  103. if (status != NSS_STATUS_SUCCESS) \
  104. { \
  105. *errnop = errno; \
  106. H_ERRNO_SET (NETDB_INTERNAL); \
  107. return status; \
  108. } \
  109. \
  110. const struct nss_db_header *header = state.header; \
  111. int i; \
  112. for (i = 0; i < header->ndbs; ++i) \
  113. if (header->dbs[i].id == db_char) \
  114. break; \
  115. if (i == header->ndbs) \
  116. { \
  117. status = NSS_STATUS_UNAVAIL; \
  118. goto out; \
  119. } \
  120. \
  121. char *key; \
  122. if (db_char == '.') \
  123. key = (char *) IGNOREPATTERN keypattern; \
  124. else \
  125. { \
  126. const size_t size = (keysize) + 1; \
  127. key = alloca (size); \
  128. \
  129. KEYPRINTF keypattern; \
  130. } \
  131. \
  132. const stridx_t *hashtable \
  133. = (const stridx_t *) ((const char *) header \
  134. + header->dbs[i].hashoffset); \
  135. const char *valstrtab = (const char *) header + header->valstroffset; \
  136. uint32_t hashval = __hash_string (key); \
  137. size_t hidx = hashval % header->dbs[i].hashsize; \
  138. size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); \
  139. \
  140. status = NSS_STATUS_NOTFOUND; \
  141. while (hashtable[hidx] != ~((stridx_t) 0)) \
  142. { \
  143. const char *valstr = valstrtab + hashtable[hidx]; \
  144. size_t len = strlen (valstr) + 1; \
  145. if (len > buflen) \
  146. { \
  147. /* No room to copy the data to. */ \
  148. *errnop = ERANGE; \
  149. H_ERRNO_SET (NETDB_INTERNAL); \
  150. status = NSS_STATUS_TRYAGAIN; \
  151. break; \
  152. } \
  153. \
  154. /* Copy the string to a place where it can be modified. */ \
  155. char *p = memcpy (buffer, valstr, len); \
  156. \
  157. int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS); \
  158. \
  159. /* Advance before break_if_match, lest it uses continue to skip
  160. to the next entry. */ \
  161. if ((hidx += hval2) >= header->dbs[i].hashsize) \
  162. hidx -= header->dbs[i].hashsize; \
  163. \
  164. if (err > 0) \
  165. { \
  166. status = NSS_STATUS_SUCCESS; \
  167. break_if_match; \
  168. status = NSS_STATUS_NOTFOUND; \
  169. } \
  170. else if (err == -1) \
  171. { \
  172. H_ERRNO_SET (NETDB_INTERNAL); \
  173. status = NSS_STATUS_TRYAGAIN; \
  174. break; \
  175. } \
  176. } \
  177. \
  178. if (status == NSS_STATUS_NOTFOUND) \
  179. H_ERRNO_SET (HOST_NOT_FOUND); \
  180. \
  181. out: \
  182. internal_endent (&state); \
  183. \
  184. return status; \
  185. }
  186. #define KEYPRINTF(pattern, args...) snprintf (key, size, pattern ,##args)
  187. #define IGNOREPATTERN(pattern, arg1, args...) (char *) (uintptr_t) arg1
  188. /* Return the next entry from the database file, doing locking. */
  189. enum nss_status
  190. CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
  191. size_t buflen, int *errnop H_ERRNO_PROTO)
  192. {
  193. /* Return next entry in host file. */
  194. enum nss_status status;
  195. struct parser_data *data = (void *) buffer;
  196. if (buflen < sizeof *data)
  197. {
  198. *errnop = ERANGE;
  199. H_ERRNO_SET (NETDB_INTERNAL);
  200. return NSS_STATUS_TRYAGAIN;
  201. }
  202. __libc_lock_lock (lock);
  203. if (state.header == NULL)
  204. {
  205. status = internal_setent (DBFILE, &state);
  206. if (status != NSS_STATUS_SUCCESS)
  207. {
  208. *errnop = errno;
  209. H_ERRNO_SET (NETDB_INTERNAL);
  210. goto out;
  211. }
  212. entidx = NULL;
  213. }
  214. /* Start from the beginning if freshly initialized or reset
  215. requested by set*ent. */
  216. if (entidx == NULL)
  217. entidx = (const char *) state.header + state.header->valstroffset;
  218. status = NSS_STATUS_UNAVAIL;
  219. if (state.header != MAP_FAILED)
  220. {
  221. const char *const end = ((const char *) state.header
  222. + state.header->valstroffset
  223. + state.header->valstrlen);
  224. while (entidx < end)
  225. {
  226. const char *next = rawmemchr (entidx, '\0') + 1;
  227. size_t len = next - entidx;
  228. if (len > buflen)
  229. {
  230. /* No room to copy the data to. */
  231. *errnop = ERANGE;
  232. H_ERRNO_SET (NETDB_INTERNAL);
  233. status = NSS_STATUS_TRYAGAIN;
  234. break;
  235. }
  236. /* Copy the string to a place where it can be modified. */
  237. char *p = memcpy (buffer, entidx, len);
  238. int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS);
  239. if (err > 0)
  240. {
  241. status = NSS_STATUS_SUCCESS;
  242. entidx = next;
  243. break;
  244. }
  245. if (err < 0)
  246. {
  247. H_ERRNO_SET (NETDB_INTERNAL);
  248. status = NSS_STATUS_TRYAGAIN;
  249. break;
  250. }
  251. /* Continue with the next record, this one is ill-formed. */
  252. entidx = next;
  253. }
  254. }
  255. out:
  256. __libc_lock_unlock (lock);
  257. return status;
  258. }