123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /* Common code for DB-based databases in nss_db module.
- Copyright (C) 1996-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
- #include <dlfcn.h>
- #include <fcntl.h>
- #include <stdint.h>
- #include <sys/mman.h>
- #include <libc-lock.h>
- #include "nsswitch.h"
- #include "nss_db.h"
- /* The hashing function we use. */
- #include "../intl/hash-string.h"
- /* These symbols are defined by the including source file:
- ENTNAME -- database name of the structure and functions (hostent, pwent).
- STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
- DATABASE -- database file name, ("hosts", "passwd")
- NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
- */
- #define ENTNAME_r CONCAT(ENTNAME,_r)
- #include <paths.h>
- #define DBFILE _PATH_VARDB DATABASE ".db"
- #ifdef NEED_H_ERRNO
- # define H_ERRNO_PROTO , int *herrnop
- # define H_ERRNO_ARG , herrnop
- # define H_ERRNO_SET(val) (*herrnop = (val))
- #else
- # define H_ERRNO_PROTO
- # define H_ERRNO_ARG
- # define H_ERRNO_SET(val) ((void) 0)
- #endif
- /* State for this database. */
- static struct nss_db_map state;
- /* Lock to protect the state and global variables. */
- __libc_lock_define (static , lock);
- /* Maintenance of the shared handle open on the database. */
- static int keep_db;
- static const char *entidx;
- /* Open the database. */
- enum nss_status
- CONCAT(_nss_db_set,ENTNAME) (int stayopen)
- {
- enum nss_status status;
- __libc_lock_lock (lock);
- status = internal_setent (DBFILE, &state);
- if (status == NSS_STATUS_SUCCESS)
- {
- /* Remember STAYOPEN flag. */
- keep_db |= stayopen;
- /* Reset the sequential index. */
- entidx = NULL;
- }
- __libc_lock_unlock (lock);
- return status;
- }
- /* Close it again. */
- enum nss_status
- CONCAT(_nss_db_end,ENTNAME) (void)
- {
- __libc_lock_lock (lock);
- internal_endent (&state);
- /* Reset STAYOPEN flag. */
- keep_db = 0;
- __libc_lock_unlock (lock);
- return NSS_STATUS_SUCCESS;
- }
- /* Macro for defining lookup functions for this DB-based database.
- NAME is the name of the lookup; e.g. `pwnam'.
- DB_CHAR is index indicator for the database.
- KEYPATTERN gives `printf' args to construct a key string;
- e.g. `("%d", id)'.
- KEYSIZE gives the allocation size of a buffer to construct it in;
- e.g. `1 + sizeof (id) * 4'.
- PROTO is the potentially empty list of other parameters.
- BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
- to the lookup key arguments and does `break;' if they match. */
- #define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
- enum nss_status \
- _nss_db_get##name##_r (proto, struct STRUCTURE *result, \
- char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\
- { \
- struct parser_data *data = (void *) buffer; \
- \
- if (buflen < sizeof *data) \
- { \
- *errnop = ERANGE; \
- H_ERRNO_SET (NETDB_INTERNAL); \
- return NSS_STATUS_TRYAGAIN; \
- } \
- \
- struct nss_db_map state = { NULL, 0 }; \
- enum nss_status status = internal_setent (DBFILE, &state); \
- if (status != NSS_STATUS_SUCCESS) \
- { \
- *errnop = errno; \
- H_ERRNO_SET (NETDB_INTERNAL); \
- return status; \
- } \
- \
- const struct nss_db_header *header = state.header; \
- int i; \
- for (i = 0; i < header->ndbs; ++i) \
- if (header->dbs[i].id == db_char) \
- break; \
- if (i == header->ndbs) \
- { \
- status = NSS_STATUS_UNAVAIL; \
- goto out; \
- } \
- \
- char *key; \
- if (db_char == '.') \
- key = (char *) IGNOREPATTERN keypattern; \
- else \
- { \
- const size_t size = (keysize) + 1; \
- key = alloca (size); \
- \
- KEYPRINTF keypattern; \
- } \
- \
- const stridx_t *hashtable \
- = (const stridx_t *) ((const char *) header \
- + header->dbs[i].hashoffset); \
- const char *valstrtab = (const char *) header + header->valstroffset; \
- uint32_t hashval = __hash_string (key); \
- size_t hidx = hashval % header->dbs[i].hashsize; \
- size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); \
- \
- status = NSS_STATUS_NOTFOUND; \
- while (hashtable[hidx] != ~((stridx_t) 0)) \
- { \
- const char *valstr = valstrtab + hashtable[hidx]; \
- size_t len = strlen (valstr) + 1; \
- if (len > buflen) \
- { \
- /* No room to copy the data to. */ \
- *errnop = ERANGE; \
- H_ERRNO_SET (NETDB_INTERNAL); \
- status = NSS_STATUS_TRYAGAIN; \
- break; \
- } \
- \
- /* Copy the string to a place where it can be modified. */ \
- char *p = memcpy (buffer, valstr, len); \
- \
- int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS); \
- \
- /* Advance before break_if_match, lest it uses continue to skip
- to the next entry. */ \
- if ((hidx += hval2) >= header->dbs[i].hashsize) \
- hidx -= header->dbs[i].hashsize; \
- \
- if (err > 0) \
- { \
- status = NSS_STATUS_SUCCESS; \
- break_if_match; \
- status = NSS_STATUS_NOTFOUND; \
- } \
- else if (err == -1) \
- { \
- H_ERRNO_SET (NETDB_INTERNAL); \
- status = NSS_STATUS_TRYAGAIN; \
- break; \
- } \
- } \
- \
- if (status == NSS_STATUS_NOTFOUND) \
- H_ERRNO_SET (HOST_NOT_FOUND); \
- \
- out: \
- internal_endent (&state); \
- \
- return status; \
- }
- #define KEYPRINTF(pattern, args...) snprintf (key, size, pattern ,##args)
- #define IGNOREPATTERN(pattern, arg1, args...) (char *) (uintptr_t) arg1
- /* Return the next entry from the database file, doing locking. */
- enum nss_status
- CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
- size_t buflen, int *errnop H_ERRNO_PROTO)
- {
- /* Return next entry in host file. */
- enum nss_status status;
- struct parser_data *data = (void *) buffer;
- if (buflen < sizeof *data)
- {
- *errnop = ERANGE;
- H_ERRNO_SET (NETDB_INTERNAL);
- return NSS_STATUS_TRYAGAIN;
- }
- __libc_lock_lock (lock);
- if (state.header == NULL)
- {
- status = internal_setent (DBFILE, &state);
- if (status != NSS_STATUS_SUCCESS)
- {
- *errnop = errno;
- H_ERRNO_SET (NETDB_INTERNAL);
- goto out;
- }
- entidx = NULL;
- }
- /* Start from the beginning if freshly initialized or reset
- requested by set*ent. */
- if (entidx == NULL)
- entidx = (const char *) state.header + state.header->valstroffset;
- status = NSS_STATUS_UNAVAIL;
- if (state.header != MAP_FAILED)
- {
- const char *const end = ((const char *) state.header
- + state.header->valstroffset
- + state.header->valstrlen);
- while (entidx < end)
- {
- const char *next = rawmemchr (entidx, '\0') + 1;
- size_t len = next - entidx;
- if (len > buflen)
- {
- /* No room to copy the data to. */
- *errnop = ERANGE;
- H_ERRNO_SET (NETDB_INTERNAL);
- status = NSS_STATUS_TRYAGAIN;
- break;
- }
- /* Copy the string to a place where it can be modified. */
- char *p = memcpy (buffer, entidx, len);
- int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS);
- if (err > 0)
- {
- status = NSS_STATUS_SUCCESS;
- entidx = next;
- break;
- }
- if (err < 0)
- {
- H_ERRNO_SET (NETDB_INTERNAL);
- status = NSS_STATUS_TRYAGAIN;
- break;
- }
- /* Continue with the next record, this one is ill-formed. */
- entidx = next;
- }
- }
- out:
- __libc_lock_unlock (lock);
- return status;
- }
|