diff options
author | Jeff Johnston <jjohnstn@redhat.com> | 2008-05-22 21:30:28 +0000 |
---|---|---|
committer | Jeff Johnston <jjohnstn@redhat.com> | 2008-05-22 21:30:28 +0000 |
commit | 3c77dcff9ebf51910b01ca770f7a8ffef52b617c (patch) | |
tree | 8424a3ed0b00dfcb1d31428f57817fadf658ba80 /newlib/libc/sys/linux/net/nsswitch.c | |
parent | 8a179967e670032fb2decf0ebcdd0059f9d139d8 (diff) | |
download | cygnal-3c77dcff9ebf51910b01ca770f7a8ffef52b617c.tar.gz cygnal-3c77dcff9ebf51910b01ca770f7a8ffef52b617c.tar.bz2 cygnal-3c77dcff9ebf51910b01ca770f7a8ffef52b617c.zip |
2008-05-22 Jeff Johnston <jjohnstn@redhat.com>
* libc/include/sys/reent.h: Add _h_errno field.
* libc/sys/linux/libc-symbols.h: Add default stubs for new libc macros
now used in net directory.
* libc/sys/linux/bits/libc-lock.h: Always define _IO_MTSAFE_IO.
* libc/sys/linux/include/hesiod.h: Add needed macros for new code
in net directory.
* libc/sys/linux/include/netdb.h: Ditto.
* libc/sys/linux/include/resolv.h: Ditto.
* libc/sys/linux/include/stdint.h: Ditto.
* libc/sys/linux/include/arpa/nameser.h: Ditto.
* libc/sys/linux/include/net/ethernet.h: Ditto.
* libc/sys/linux/include/net/if_ppp.h: Ditto.
* libc/sys/linux/include/netinet/if_ether.h: Ditto.
* libc/sys/linux/machine/i386/get_clockfreq.c: Remove static memmem.
* libc/sys/linux/machine/i386/include/endian.h: Protect macros with
flags to avoid duplicate definition.
* libc/sys/linux/machine/i386/include/param.h: Ditto.
* libc/sys/linux/net/Makefile.am: Modified to account for removed and
added files.
* libc/sys/linux/net/Makefile.in: Regenerated.
* libc/sys/linux/net/base64.c: Replaced with glibc version of code.
* libc/sys/linux/net/getaddrinfo.c: Ditto.
* libc/sys/linux/net/getnameinfo.c: Ditto.
* libc/sys/linux/net/getproto.c: Ditto.
* libc/sys/linux/net/getservent.c: Ditto.
* libc/sys/linux/net/inet_netof.c: Ditto.
* libc/sys/linux/net/inet_lnaof.c: Ditto.
* libc/sys/linux/net/ns_name.c: Ditto.
* libc/sys/linux/net/ns_netint.c: Ditto.
* libc/sys/linux/net/inet_ntoa.c: Ditto.
* libc/sys/linux/net/ns_parse.c: Ditto.
* libc/sys/linux/net/ns_print.c: Ditto.
* libc/sys/linux/net/ns_ttl.c: Ditto.
* libc/sys/linux/net/nsap_addr.c: Ditto.
* libc/sys/linux/net/rcmd.c: Ditto.
* libc/sys/linux/net/res_comp.c: Ditto.
* libc/sys/linux/net/res_data.c: Ditto.
* libc/sys/linux/net/res_debug.c: Ditto.
* libc/sys/linux/net/res_init.c: Ditto.
* libc/sys/linux/net/res_mkquery.c: Ditto.
* libc/sys/linux/net/res_query.c: Ditto.
* libc/sys/linux/net/res_send.c: Ditto.
* libc/sys/linux/net/send.c: Ditto.
* libc/sys/linux/stdlib/collate.c: Ditto.
* libc/sys/linux/sys/ioctl.h: Ditto.
* libc/sys/linux/sys/socket.h: Ditto.
* libc/sys/linux/sys/unistd.h: Ditto.
* libc/sys/linux/iconv/iconvconfig.c: Removed either because no longer
used or because licensing includes advertising clause that cannot be
ignored.
* libc/sys/linux/iconv/strtab.c: Ditto.
* libc/sys/linux/include/libc_private.h: Ditto.
* libc/sys/linux/include/nsswitch.h: Ditto.
* libc/sys/linux/include/net/if_atm.h: Ditto.
* libc/sys/linux/include/net/if_media.h: Ditto.
* libc/sys/linux/include/net/if_pppvar.h: Ditto.
* libc/sys/linux/include/netinet/if_atm.h: Ditto.
* libc/sys/linux/include/netinet/ip_flow.h: Ditto.
* libc/sys/linux/intl/locale.alias: Ditto.
* libc/sys/linux/net/addr2ascii.3: Ditto.
* libc/sys/linux/net/bindresvport.c: Ditto.
* libc/sys/linux/net/byteorder.3: Ditto.
* libc/sys/linux/net/res_config.h: Ditto.
* libc/sys/linux/net/ether_addr.c: Ditto.
* libc/sys/linux/net/ethers.3: Ditto.
* libc/sys/linux/net/getaddrinfo.3: Ditto.
* libc/sys/linux/net/gethostbydns.c: Ditto.
* libc/sys/linux/net/gethostbyht.c: Ditto.
* libc/sys/linux/net/gethostbyname.3: Ditto.
* libc/sys/linux/net/gethostbynis.c: Ditto.
* libc/sys/linux/net/gethostnamadr.c: Ditto.
* libc/sys/linux/net/getifaddrs.3: Ditto.
* libc/sys/linux/net/getifaddrs.c: Ditto.
* libc/sys/linux/net/getipnodebyname.3: Ditto.
* libc/sys/linux/net/getnameinfo.3: Ditto.
* libc/sys/linux/net/getnetbydns.c: Ditto.
* libc/sys/linux/net/getnetbyht.c: Ditto.
* libc/sys/linux/net/getnetbynis.c: Ditto.
* libc/sys/linux/net/getnetent.3: Ditto.
* libc/sys/linux/net/getnetnamadr.c: Ditto.
* libc/sys/linux/net/getprotoent.3: Ditto.
* libc/sys/linux/net/getprotoent.c: Ditto.
* libc/sys/linux/net/getprotoname.c: Ditto.
* libc/sys/linux/net/getservbyname.c: Ditto.
* libc/sys/linux/net/getservbyport.c: Ditto.
* libc/sys/linux/net/getservent.3: Ditto.
* libc/sys/linux/net/herror.c: Ditto.
* libc/sys/linux/net/hesiod.3: Ditto.
* libc/sys/linux/net/hesiod.c: Ditto.
* libc/sys/linux/net/if_indextoname.3: Ditto.
* libc/sys/linux/net/inet.3: Ditto.
* libc/sys/linux/net/inet6_option_space.3: Ditto.
* libc/sys/linux/net/inet6_rthdr_space.3: Ditto.
* libc/sys/linux/net/inet_makeaddr.c: Ditto.
* libc/sys/linux/net/inet_net.3: Ditto.
* libc/sys/linux/net/inet_network.c: Ditto.
* libc/sys/linux/net/innetgr-stub.c: Ditto.
* libc/sys/linux/net/ip6opt.c: Ditto.
* libc/sys/linux/net/iso_addr.3: Ditto.
* libc/sys/linux/net/iso_addr.c: Ditto.
* libc/sys/linux/net/linkaddr.3: Ditto.
* libc/sys/linux/net/linkaddr.c: Ditto.
* libc/sys/linux/net/map_v4v6.c: Ditto.
* libc/sys/linux/net/name6.c: Ditto.
* libc/sys/linux/net/namespace.h: Ditto.
* libc/sys/linux/net/ns.3: Ditto.
* libc/sys/linux/net/ns_addr.c: Ditto.
* libc/sys/linux/net/ns_ntoa.c: Ditto.
* libc/sys/linux/net/nsdispatch.3: Ditto.
* libc/sys/linux/net/nsdispatch.c: Ditto.
* libc/sys/linux/net/nslexer.c: Ditto.
* libc/sys/linux/net/nslexer.l: Ditto.
* libc/sys/linux/net/nsparser.c: Ditto.
* libc/sys/linux/net/nsparser.h: Ditto.
* libc/sys/linux/net/nsparser.y: Ditto.
* libc/sys/linux/net/rcmd.3: Ditto.
* libc/sys/linux/net/rcmdsh.3: Ditto.
* libc/sys/linux/net/res_mkupdate.c: Ditto.
* libc/sys/linux/net/res_update.c: Ditto.
* libc/sys/linux/net/resolver.3: Ditto.
* libc/sys/linux/net/rthdr.c: Ditto.
* libc/sys/linux/net/vars.c: Ditto.
* libc/sys/linux/shlib-compat.h: New file.
* libc/sys/linux/machine/i386/atomic.h: Ditto.
* libc/sys/linux/net/XXX-lookup.c: Ditto.
* libc/sys/linux/net/alias-lookup.c: Ditto.
* libc/sys/linux/net/res_libc.c: Ditto.
* libc/sys/linux/net/aliases.h: Ditto.
* libc/sys/linux/net/check_pf.c: Ditto.
* libc/sys/linux/net/databases.def: Ditto.
* libc/sys/linux/net/digits_dots.c: Ditto.
* libc/sys/linux/net/ether_aton.c: Ditto.
* libc/sys/linux/net/ether_aton_r.c: Ditto.
* libc/sys/linux/net/ether_hton.c: Ditto.
* libc/sys/linux/net/ether_line.c: Ditto.
* libc/sys/linux/net/ether_ntoa.c: Ditto.
* libc/sys/linux/net/ether_ntoa_r.c: Ditto.
* libc/sys/linux/net/ether_ntoh.c: Ditto.
* libc/sys/linux/net/etherent.h: Ditto.
* libc/sys/linux/net/ethers-lookup.c: Ditto.
* libc/sys/linux/net/function.def: Ditto.
* libc/sys/linux/net/getXXbyYY.c: Ditto.
* libc/sys/linux/net/getXXbyYY_r.c: Ditto.
* libc/sys/linux/net/getXXent.c: Ditto.
* libc/sys/linux/net/getXXent_r.c: Ditto.
* libc/sys/linux/net/getaliasent.c: Ditto.
* libc/sys/linux/net/getaliasent_r.c: Ditto.
* libc/sys/linux/net/getaliasname.c: Ditto.
* libc/sys/linux/net/getaliasname_r.c: Ditto.
* libc/sys/linux/net/gethstbyad.c: Ditto.
* libc/sys/linux/net/gethstbyad_r.c: Ditto.
* libc/sys/linux/net/gethstbynm.c: Ditto.
* libc/sys/linux/net/gethstbynm2.c: Ditto.
* libc/sys/linux/net/gethstbynm2_r.c: Ditto.
* libc/sys/linux/net/gethstbynm_r.c: Ditto.
* libc/sys/linux/net/gethstent.c: Ditto.
* libc/sys/linux/net/gethstent_r.c: Ditto.
* libc/sys/linux/net/getnetbyad.c: Ditto.
* libc/sys/linux/net/getnetbyad_r.c: Ditto.
* libc/sys/linux/net/getnetbynm.c: Ditto.
* libc/sys/linux/net/getnetbynm_r.c: Ditto.
* libc/sys/linux/net/getnetent.c: Ditto.
* libc/sys/linux/net/getnetent_r.c: Ditto.
* libc/sys/linux/net/getnetgrent.c: Ditto.
* libc/sys/linux/net/getnetgrent_r.c: Ditto.
* libc/sys/linux/net/getnssent.c: Ditto.
* libc/sys/linux/net/getnssent_r.c: Ditto.
* libc/sys/linux/net/getproto_r.c: Ditto.
* libc/sys/linux/net/getprtent.c: Ditto.
* libc/sys/linux/net/getprtent_r.c: Ditto.
* libc/sys/linux/net/getprtname.c: Ditto.
* libc/sys/linux/net/getprtname_r.c: Ditto.
* libc/sys/linux/net/getrpcbyname.c: Ditto.
* libc/sys/linux/net/getrpcbyname_r.c: Ditto.
* libc/sys/linux/net/getrpcbynumber.c: Ditto.
* libc/sys/linux/net/getrpcbynumber_r.c: Ditto.
* libc/sys/linux/net/getrpcent.c: Ditto.
* libc/sys/linux/net/getrpcent_r.c: Ditto.
* libc/sys/linux/net/getservent_r.c: Ditto.
* libc/sys/linux/net/getsrvbynm.c: Ditto.
* libc/sys/linux/net/getsrvbynm_r.c: Ditto.
* libc/sys/linux/net/getsrvbypt.c: Ditto.
* libc/sys/linux/net/getsrvbypt_r.c: Ditto.
* libc/sys/linux/net/grp-lookup.c: Ditto.
* libc/sys/linux/net/herrno.c: Ditto.
* libc/sys/linux/net/hosts-lookup.c: Ditto.
* libc/sys/linux/net/ifaddrs.h: Ditto.
* libc/sys/linux/net/ifreq.c: Ditto.
* libc/sys/linux/net/ifreq.h: Ditto.
* libc/sys/linux/net/in6_addr.c: Ditto.
* libc/sys/linux/net/inet6_option.c: Ditto.
* libc/sys/linux/net/inet_mkadr.c: Ditto.
* libc/sys/linux/net/inet_net.c: Ditto.
* libc/sys/linux/net/key-lookup.c: Ditto.
* libc/sys/linux/net/local.h: Ditto.
* libc/sys/linux/net/netgroup.h: Ditto.
* libc/sys/linux/net/netgrp-lookup.c: Ditto.
* libc/sys/linux/net/network-lookup.c: Ditto.
* libc/sys/linux/net/not-cancel.h: Ditto.
* libc/sys/linux/net/ns_samedomain.c: Ditto.
* libc/sys/linux/net/nscd-types.h: Ditto.
* libc/sys/linux/net/nss.h: Ditto.
* libc/sys/linux/net/nsswitch.c: Ditto.
* libc/sys/linux/net/nsswitch.h: Ditto.
* libc/sys/linux/net/opensock.c: Ditto.
* libc/sys/linux/net/proto-lookup.c: Ditto.
* libc/sys/linux/net/pwd-lookup.c: Ditto.
* libc/sys/linux/net/res_debug.h: Ditto.
* libc/sys/linux/net/res_hconf.c: Ditto.
* libc/sys/linux/net/res_hconf.h: Ditto.
* libc/sys/linux/net/rexec.c: Ditto.
* libc/sys/linux/net/rpc-lookup.c: Ditto.
* libc/sys/linux/net/ruserpass.c: Ditto.
* libc/sys/linux/net/service-lookup.c: Ditto.
* libc/sys/linux/net/spwd-lookup.c: Ditto.
* libc/sys/linux/net/nscd/nscd-client.h: Ditto.
* libc/sys/linux/net/nscd/nscd_proto.h: Ditto.
Diffstat (limited to 'newlib/libc/sys/linux/net/nsswitch.c')
-rw-r--r-- | newlib/libc/sys/linux/net/nsswitch.c | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/newlib/libc/sys/linux/net/nsswitch.c b/newlib/libc/sys/linux/net/nsswitch.c new file mode 100644 index 000000000..6c5d1f8e9 --- /dev/null +++ b/newlib/libc/sys/linux/net/nsswitch.c @@ -0,0 +1,772 @@ +/* Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <ctype.h> +#include <dlfcn.h> +#include <errno.h> +#include <netdb.h> +#include <bits/libc-lock.h> +#include <search.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> + +#include <aliases.h> +#include <grp.h> +#include <netinet/ether.h> +#include <pwd.h> +#include <shadow.h> + +#include "local.h" + +#if !defined DO_STATIC_NSS || defined SHARED +# include <gnu/lib-names.h> +#endif + +#include "nsswitch.h" +#include "nscd/nscd_proto.h" + +/* Prototypes for the local functions. */ +static name_database *nss_parse_file (const char *fname) internal_function; +static name_database_entry *nss_getline (char *line) internal_function; +static service_user *nss_parse_service_list (const char *line) + internal_function; +static service_library *nss_new_service (name_database *database, + const char *name) internal_function; + + +/* Declare external database variables. */ +#define DEFINE_DATABASE(name) \ + extern service_user *__nss_##name##_database attribute_hidden; \ + weak_extern (__nss_##name##_database) +#include "databases.def" +#undef DEFINE_DATABASE + +/* Structure to map database name to variable. */ +static struct +{ + const char *name; + service_user **dbp; +} databases[] = +{ +#define DEFINE_DATABASE(name) \ + { #name, &__nss_##name##_database }, +#include "databases.def" +#undef DEFINE_DATABASE +}; + + +__libc_lock_define_initialized (static, lock) + +#if !defined DO_STATIC_NSS || defined SHARED +/* String with revision number of the shared object files. */ +static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; +#endif + +/* The root of the whole data base. */ +static name_database *service_table; + + +/* -1 == database not found + 0 == database entry pointer stored */ +int +__nss_database_lookup (const char *database, const char *alternate_name, + const char *defconfig, service_user **ni) +{ + /* Prevent multiple threads to change the service table. */ + __libc_lock_lock (lock); + + /* Reconsider database variable in case some other thread called + `__nss_configure_lookup' while we waited for the lock. */ + if (*ni != NULL) + { + __libc_lock_unlock (lock); + return 0; + } + + /* Are we initialized yet? */ + if (service_table == NULL) + /* Read config file. */ + service_table = nss_parse_file (_PATH_NSSWITCH_CONF); + + /* Test whether configuration data is available. */ + if (service_table != NULL) + { + /* Return first `service_user' entry for DATABASE. */ + name_database_entry *entry; + + /* XXX Could use some faster mechanism here. But each database is + only requested once and so this might not be critical. */ + for (entry = service_table->entry; entry != NULL; entry = entry->next) + if (strcmp (database, entry->name) == 0) + *ni = entry->service; + + if (*ni == NULL && alternate_name != NULL) + /* We haven't found an entry so far. Try to find it with the + alternative name. */ + for (entry = service_table->entry; entry != NULL; entry = entry->next) + if (strcmp (alternate_name, entry->name) == 0) + *ni = entry->service; + } + + /* No configuration data is available, either because nsswitch.conf + doesn't exist or because it doesn't has a line for this database. + + DEFCONFIG specifies the default service list for this database, + or null to use the most common default. */ + if (*ni == NULL) + *ni = nss_parse_service_list (defconfig + ?: "nis [NOTFOUND=return] files"); + + __libc_lock_unlock (lock); + + return 0; +} +libc_hidden_def (__nss_database_lookup) + + +/* -1 == not found + 0 == function found + 1 == finished */ +int +__nss_lookup (service_user **ni, const char *fct_name, void **fctp) +{ + *fctp = __nss_lookup_function (*ni, fct_name); + + while (*fctp == NULL + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE + && (*ni)->next != NULL) + { + *ni = (*ni)->next; + + *fctp = __nss_lookup_function (*ni, fct_name); + } + + return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1; +} + + +/* -1 == not found + 0 == adjusted for next function + 1 == finished */ +int +__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, + int all_values) +{ + if (all_values) + { + if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN + && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN + && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN) + return 1; + } + else + { + /* This is really only for debugging. */ + if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) + { + fprintf (stderr, "illegal status in __nss_next"); + abort(); + } + + if (nss_next_action (*ni, status) == NSS_ACTION_RETURN) + return 1; + } + + if ((*ni)->next == NULL) + return -1; + + do + { + *ni = (*ni)->next; + + *fctp = __nss_lookup_function (*ni, fct_name); + } + while (*fctp == NULL + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE + && (*ni)->next != NULL); + + return *fctp != NULL ? 0 : -1; +} +libc_hidden_def (__nss_next) + + +int +__nss_configure_lookup (const char *dbname, const char *service_line) +{ + service_user *new_db; + size_t cnt; + + for (cnt = 0; cnt < sizeof databases; ++cnt) + { + int cmp = strcmp (dbname, databases[cnt].name); + if (cmp == 0) + break; + if (cmp < 0) + { + __set_errno (EINVAL); + return -1; + } + } + + if (cnt == sizeof databases) + { + __set_errno (EINVAL); + return -1; + } + + /* Test whether it is really used. */ + if (databases[cnt].dbp == NULL) + /* Nothing to do, but we could do. */ + return 0; + + /* Try to generate new data. */ + new_db = nss_parse_service_list (service_line); + if (new_db == NULL) + { + /* Illegal service specification. */ + __set_errno (EINVAL); + return -1; + } + + /* Prevent multiple threads to change the service table. */ + __libc_lock_lock (lock); + + /* Install new rules. */ + *databases[cnt].dbp = new_db; + + __libc_lock_unlock (lock); + + return 0; +} + + +/* Comparison function for searching NI->known tree. */ +static int +known_compare (const void *p1, const void *p2) +{ + return p1 == p2 ? 0 : strcmp (*(const char *const *) p1, + *(const char *const *) p2); +} + + +void * +__nss_lookup_function (service_user *ni, const char *fct_name) +{ + void **found, *result; + + /* We now modify global data. Protect it. */ + __libc_lock_lock (lock); + + /* Search the tree of functions previously requested. Data in the + tree are `known_function' structures, whose first member is a + `const char *', the lookup key. The search returns a pointer to + the tree node structure; the first member of the is a pointer to + our structure (i.e. what will be a `known_function'); since the + first member of that is the lookup key string, &FCT_NAME is close + enough to a pointer to our structure to use as a lookup key that + will be passed to `known_compare' (above). */ + + found = tsearch (&fct_name, (void **) &ni->known, &known_compare); + if (*found != &fct_name) + /* The search found an existing structure in the tree. */ + result = ((known_function *) *found)->fct_ptr; + else + { + /* This name was not known before. Now we have a node in the tree + (in the proper sorted position for FCT_NAME) that points to + &FCT_NAME instead of any real `known_function' structure. + Allocate a new structure and fill it in. */ + + known_function *known = malloc (sizeof *known); + if (! known) + { + remove_from_tree: + /* Oops. We can't instantiate this node properly. + Remove it from the tree. */ + tdelete (&fct_name, (void **) &ni->known, &known_compare); + result = NULL; + } + else + { + /* Point the tree node at this new structure. */ + *found = known; + known->fct_name = fct_name; + + if (ni->library == NULL) + { + /* This service has not yet been used. Fetch the service + library for it, creating a new one if need be. If there + is no service table from the file, this static variable + holds the head of the service_library list made from the + default configuration. */ + static name_database default_table; + ni->library = nss_new_service (service_table ?: &default_table, + ni->name); + if (ni->library == NULL) + { + /* This only happens when out of memory. */ + free (known); + goto remove_from_tree; + } + } + +#if !defined DO_STATIC_NSS || defined SHARED + if (ni->library->lib_handle == NULL) + { + /* Load the shared library. */ + size_t shlen = (7 + strlen (ni->library->name) + 3 + + strlen (__nss_shlib_revision) + 1); + int saved_errno = errno; + char shlib_name[shlen]; + + /* Construct shared object name. */ + stpcpy (stpcpy (stpcpy (stpcpy (shlib_name, + "libnss_"), + ni->library->name), + ".so"), + __nss_shlib_revision); + + ni->library->lib_handle = __libc_dlopen (shlib_name); + if (ni->library->lib_handle == NULL) + { + /* Failed to load the library. */ + ni->library->lib_handle = (void *) -1l; + __set_errno (saved_errno); + } + } + + if (ni->library->lib_handle == (void *) -1l) + /* Library not found => function not found. */ + result = NULL; + else + { + /* Get the desired function. */ + size_t namlen = (5 + strlen (ni->library->name) + 1 + + strlen (fct_name) + 1); + char name[namlen]; + + /* Construct the function name. */ + stpcpy (stpcpy (stpcpy (stpcpy (name, "_nss_"), + ni->library->name), + "_"), + fct_name); + + /* Look up the symbol. */ + result = __libc_dlsym (ni->library->lib_handle, name); + } +#else + /* We can't get function address dynamically in static linking. */ + { +# define DEFINE_ENT(h,nm) \ + { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \ + { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \ + { #h"_set"#nm"ent", _nss_##h##_set##nm##ent }, +# define DEFINE_GET(h,nm) \ + { #h"_get"#nm"_r", _nss_##h##_get##nm##_r }, +# define DEFINE_GETBY(h,nm,ky) \ + { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r }, + static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] = + { +# include "function.def" + { NULL, NULL } + }; + size_t namlen = (5 + strlen (ni->library->name) + 1 + + strlen (fct_name) + 1); + char name[namlen]; + + /* Construct the function name. */ + stpcpy (stpcpy (stpcpy (name, ni->library->name), + "_"), + fct_name); + + result = NULL; + for (tp = &tbl[0]; tp->fname; tp++) + if (strcmp (tp->fname, name) == 0) + { + result = tp->fp; + break; + } + } +#endif + + /* Remember function pointer for later calls. Even if null, we + record it so a second try needn't search the library again. */ + known->fct_ptr = result; + } + } + + /* Remove the lock. */ + __libc_lock_unlock (lock); + + return result; +} +libc_hidden_def (__nss_lookup_function) + + +static name_database * +internal_function +nss_parse_file (const char *fname) +{ + FILE *fp; + name_database *result; + name_database_entry *last; + char *line; + size_t len; + + /* Open the configuration file. */ + fp = fopen (fname, "rc"); + if (fp == NULL) + return NULL; + + /* No threads use this stream. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + result = (name_database *) malloc (sizeof (name_database)); + if (result == NULL) + return NULL; + + result->entry = NULL; + result->library = NULL; + last = NULL; + line = NULL; + len = 0; + do + { + name_database_entry *this; + ssize_t n; + char *tmp; + + n = __getline (&line, &len, fp); + if (n < 0) + break; + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + /* Because the file format does not know any form of quoting we + can search forward for the next '#' character and if found + make it terminating the line. */ + tmp = strchr (line, '#'); + if (tmp == NULL) + tmp = line + strlen (line); + *tmp = '\0'; + + /* If the line is blank it is ignored. */ + if (line[0] == '\0') + continue; + + /* Each line completely specifies the actions for a database. */ + this = nss_getline (line); + if (this != NULL) + { + if (last != NULL) + last->next = this; + else + result->entry = this; + + last = this; + } + } + while (!feof (fp)); + + /* Free the buffer. */ + free (line); + /* Close configuration file. */ + fclose (fp); + + return result; +} + + +/* Read the source names: + `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*' + */ +static service_user * +internal_function +nss_parse_service_list (const char *line) +{ + service_user *result = NULL, **nextp = &result; + + while (1) + { + service_user *new_service; + const char *name; + + while (isspace (line[0])) + ++line; + if (line[0] == '\0') + /* No source specified. */ + return result; + + /* Read <source> identifier. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[') + ++line; + if (name == line) + return result; + + + new_service = (service_user *) malloc (sizeof (service_user) + + (line - name + 1)); + if (new_service == NULL) + return result; + + *((char *) mempcpy (new_service->name, name, line - name)) = '\0'; + + /* Set default actions. */ + new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE; + new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE; + new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE; + new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN; + new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN; + new_service->library = NULL; + new_service->known = NULL; + new_service->next = NULL; + + while (isspace (line[0])) + ++line; + + if (line[0] == '[') + { + /* Read criterions. */ + do + ++line; + while (line[0] != '\0' && isspace (line[0])); + + do + { + int not; + enum nss_status status; + lookup_actions action; + + /* Grok ! before name to mean all statii but that one. */ + not = line[0] == '!'; + if (not) + ++line; + + /* Read status name. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' + && line[0] != ']') + ++line; + + /* Compare with known statii. */ + if (line - name == 7) + { + if (strncasecmp (name, "SUCCESS", 7) == 0) + status = NSS_STATUS_SUCCESS; + else if (strncasecmp (name, "UNAVAIL", 7) == 0) + status = NSS_STATUS_UNAVAIL; + else + return result; + } + else if (line - name == 8) + { + if (strncasecmp (name, "NOTFOUND", 8) == 0) + status = NSS_STATUS_NOTFOUND; + else if (strncasecmp (name, "TRYAGAIN", 8) == 0) + status = NSS_STATUS_TRYAGAIN; + else + return result; + } + else + return result; + + while (isspace (line[0])) + ++line; + if (line[0] != '=') + return result; + do + ++line; + while (isspace (line[0])); + + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' + && line[0] != ']') + ++line; + + if (line - name == 6 && strncasecmp (name, "RETURN", 6) == 0) + action = NSS_ACTION_RETURN; + else if (line - name == 8 + && strncasecmp (name, "CONTINUE", 8) == 0) + action = NSS_ACTION_CONTINUE; + else + return result; + + if (not) + { + /* Save the current action setting for this status, + set them all to the given action, and reset this one. */ + const lookup_actions save = new_service->actions[2 + status]; + new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action; + new_service->actions[2 + NSS_STATUS_UNAVAIL] = action; + new_service->actions[2 + NSS_STATUS_NOTFOUND] = action; + new_service->actions[2 + NSS_STATUS_SUCCESS] = action; + new_service->actions[2 + status] = save; + } + else + new_service->actions[2 + status] = action; + + /* Skip white spaces. */ + while (isspace (line[0])) + ++line; + } + while (line[0] != ']'); + + /* Skip the ']'. */ + ++line; + } + + *nextp = new_service; + nextp = &new_service->next; + } +} + +static name_database_entry * +internal_function +nss_getline (char *line) +{ + const char *name; + name_database_entry *result; + size_t len; + + /* Ignore leading white spaces. ATTENTION: this is different from + what is implemented in Solaris. The Solaris man page says a line + beginning with a white space character is ignored. We regard + this as just another misfeature in Solaris. */ + while (isspace (line[0])) + ++line; + + /* Recognize `<database> ":"'. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':') + ++line; + if (line[0] == '\0' || name == line) + /* Syntax error. */ + return NULL; + *line++ = '\0'; + + len = strlen (name) + 1; + + result = (name_database_entry *) malloc (sizeof (name_database_entry) + len); + if (result == NULL) + return NULL; + + /* Save the database name. */ + memcpy (result->name, name, len); + + /* Parse the list of services. */ + result->service = nss_parse_service_list (line); + + result->next = NULL; + return result; +} + + +static service_library * +internal_function +nss_new_service (name_database *database, const char *name) +{ + service_library **currentp = &database->library; + + while (*currentp != NULL) + { + if (strcmp ((*currentp)->name, name) == 0) + return *currentp; + currentp = &(*currentp)->next; + } + + /* We have to add the new service. */ + *currentp = (service_library *) malloc (sizeof (service_library)); + if (*currentp == NULL) + return NULL; + + (*currentp)->name = name; + (*currentp)->lib_handle = NULL; + (*currentp)->next = NULL; + + return *currentp; +} + + +#ifdef USE_NSCD +/* Called by nscd and nscd alone. */ +void +__nss_disable_nscd (void) +{ + /* Disable all uses of NSCD. */ + __nss_not_use_nscd_passwd = -1; + __nss_not_use_nscd_group = -1; + __nss_not_use_nscd_hosts = -1; +} +#endif + + +/* Free all resources if necessary. */ +libc_freeres_fn (free_mem) +{ + name_database *top = service_table; + name_database_entry *entry; + service_library *library; + + if (top == NULL) + /* Maybe we have not read the nsswitch.conf file. */ + return; + + /* Don't disturb ongoing other threads (if there are any). */ + service_table = NULL; + + entry = top->entry; + while (entry != NULL) + { + name_database_entry *olde = entry; + service_user *service = entry->service; + + while (service != NULL) + { + service_user *olds = service; + + if (service->known != NULL) + tdestroy (service->known, free); + + service = service->next; + free (olds); + } + + entry = entry->next; + free (olde); + } + + library = top->library; + while (library != NULL) + { + service_library *oldl = library; + + if (library->lib_handle && library->lib_handle != (void *) -1l) + __libc_dlclose (library->lib_handle); + + library = library->next; + free (oldl); + } + + free (top); +} |