Back to index

glibc  2.9
nsswitch.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ctype.h>
00021 #include <dlfcn.h>
00022 #include <errno.h>
00023 #include <netdb.h>
00024 #include <bits/libc-lock.h>
00025 #include <search.h>
00026 #include <stdio.h>
00027 #include <stdio_ext.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 
00031 #include <aliases.h>
00032 #include <grp.h>
00033 #include <netinet/ether.h>
00034 #include <pwd.h>
00035 #include <shadow.h>
00036 
00037 #if !defined DO_STATIC_NSS || defined SHARED
00038 # include <gnu/lib-names.h>
00039 #endif
00040 
00041 #include "nsswitch.h"
00042 #include "../nscd/nscd_proto.h"
00043 
00044 /* Prototypes for the local functions.  */
00045 static name_database *nss_parse_file (const char *fname) internal_function;
00046 static name_database_entry *nss_getline (char *line) internal_function;
00047 static service_user *nss_parse_service_list (const char *line)
00048      internal_function;
00049 static service_library *nss_new_service (name_database *database,
00050                                     const char *name) internal_function;
00051 
00052 
00053 /* Declare external database variables.  */
00054 #define DEFINE_DATABASE(name)                                               \
00055   extern service_user *__nss_##name##_database attribute_hidden;            \
00056   weak_extern (__nss_##name##_database)
00057 #include "databases.def"
00058 #undef DEFINE_DATABASE
00059 
00060 /* Structure to map database name to variable.  */
00061 static const struct
00062 {
00063   const char name[10];
00064   service_user **dbp;
00065 } databases[] =
00066 {
00067 #define DEFINE_DATABASE(name)                                               \
00068   { #name, &__nss_##name##_database },
00069 #include "databases.def"
00070 #undef DEFINE_DATABASE
00071 };
00072 #define ndatabases (sizeof (databases) / sizeof (databases[0]))
00073 
00074 
00075 __libc_lock_define_initialized (static, lock)
00076 
00077 #if !defined DO_STATIC_NSS || defined SHARED
00078 /* String with revision number of the shared object files.  */
00079 static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
00080 #endif
00081 
00082 /* The root of the whole data base.  */
00083 static name_database *service_table;
00084 
00085 
00086 /* -1 == database not found
00087     0 == database entry pointer stored */
00088 int
00089 __nss_database_lookup (const char *database, const char *alternate_name,
00090                      const char *defconfig, service_user **ni)
00091 {
00092   /* Prevent multiple threads to change the service table.  */
00093   __libc_lock_lock (lock);
00094 
00095   /* Reconsider database variable in case some other thread called
00096      `__nss_configure_lookup' while we waited for the lock.  */
00097   if (*ni != NULL)
00098     {
00099       __libc_lock_unlock (lock);
00100       return 0;
00101     }
00102 
00103   /* Are we initialized yet?  */
00104   if (service_table == NULL)
00105     /* Read config file.  */
00106     service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
00107 
00108   /* Test whether configuration data is available.  */
00109   if (service_table != NULL)
00110     {
00111       /* Return first `service_user' entry for DATABASE.  */
00112       name_database_entry *entry;
00113 
00114       /* XXX Could use some faster mechanism here.  But each database is
00115         only requested once and so this might not be critical.  */
00116       for (entry = service_table->entry; entry != NULL; entry = entry->next)
00117        if (strcmp (database, entry->name) == 0)
00118          *ni = entry->service;
00119 
00120       if (*ni == NULL && alternate_name != NULL)
00121        /* We haven't found an entry so far.  Try to find it with the
00122           alternative name.  */
00123        for (entry = service_table->entry; entry != NULL; entry = entry->next)
00124          if (strcmp (alternate_name, entry->name) == 0)
00125            *ni = entry->service;
00126     }
00127 
00128   /* No configuration data is available, either because nsswitch.conf
00129      doesn't exist or because it doesn't has a line for this database.
00130 
00131      DEFCONFIG specifies the default service list for this database,
00132      or null to use the most common default.  */
00133   if (*ni == NULL)
00134     *ni = nss_parse_service_list (defconfig
00135                               ?: "nis [NOTFOUND=return] files");
00136 
00137   __libc_lock_unlock (lock);
00138 
00139   return 0;
00140 }
00141 libc_hidden_def (__nss_database_lookup)
00142 
00143 
00144 /* -1 == not found
00145     0 == function found
00146     1 == finished */
00147 int
00148 __nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name,
00149              void **fctp)
00150 {
00151   *fctp = __nss_lookup_function (*ni, fct_name);
00152   if (*fctp == NULL && fct2_name != NULL)
00153     *fctp = __nss_lookup_function (*ni, fct2_name);
00154 
00155   while (*fctp == NULL
00156         && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
00157         && (*ni)->next != NULL)
00158     {
00159       *ni = (*ni)->next;
00160 
00161       *fctp = __nss_lookup_function (*ni, fct_name);
00162       if (*fctp == NULL && fct2_name != NULL)
00163        *fctp = __nss_lookup_function (*ni, fct2_name);
00164     }
00165 
00166   return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
00167 }
00168 
00169 
00170 /* -1 == not found
00171     0 == adjusted for next function
00172     1 == finished */
00173 int
00174 __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name,
00175             void **fctp, int status, int all_values)
00176 {
00177   if (all_values)
00178     {
00179       if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
00180          && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
00181          && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
00182          && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
00183        return 1;
00184     }
00185   else
00186     {
00187       /* This is really only for debugging.  */
00188       if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
00189                          || status > NSS_STATUS_RETURN, 0))
00190         __libc_fatal ("illegal status in __nss_next");
00191 
00192        if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
00193         return 1;
00194     }
00195 
00196   if ((*ni)->next == NULL)
00197     return -1;
00198 
00199   do
00200     {
00201       *ni = (*ni)->next;
00202 
00203       *fctp = __nss_lookup_function (*ni, fct_name);
00204       if (*fctp == NULL && fct2_name != NULL)
00205        *fctp = __nss_lookup_function (*ni, fct2_name);
00206     }
00207   while (*fctp == NULL
00208         && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
00209         && (*ni)->next != NULL);
00210 
00211   return *fctp != NULL ? 0 : -1;
00212 }
00213 libc_hidden_def (__nss_next2)
00214 
00215 
00216 int
00217 attribute_compat_text_section
00218 __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
00219            int all_values)
00220 {
00221   return __nss_next2 (ni, fct_name, NULL, fctp, status, all_values);
00222 }
00223 
00224 
00225 int
00226 __nss_configure_lookup (const char *dbname, const char *service_line)
00227 {
00228   service_user *new_db;
00229   size_t cnt;
00230 
00231   for (cnt = 0; cnt < ndatabases; ++cnt)
00232     {
00233       int cmp = strcmp (dbname, databases[cnt].name);
00234       if (cmp == 0)
00235        break;
00236       if (cmp < 0)
00237        {
00238          __set_errno (EINVAL);
00239          return -1;
00240        }
00241     }
00242 
00243   if (cnt == ndatabases)
00244     {
00245       __set_errno (EINVAL);
00246       return -1;
00247     }
00248 
00249   /* Test whether it is really used.  */
00250   if (databases[cnt].dbp == NULL)
00251     /* Nothing to do, but we could do.  */
00252     return 0;
00253 
00254   /* Try to generate new data.  */
00255   new_db = nss_parse_service_list (service_line);
00256   if (new_db == NULL)
00257     {
00258       /* Illegal service specification.  */
00259       __set_errno (EINVAL);
00260       return -1;
00261     }
00262 
00263   /* Prevent multiple threads to change the service table.  */
00264   __libc_lock_lock (lock);
00265 
00266   /* Install new rules.  */
00267   *databases[cnt].dbp = new_db;
00268 
00269   __libc_lock_unlock (lock);
00270 
00271   return 0;
00272 }
00273 
00274 
00275 /* Comparison function for searching NI->known tree.  */
00276 static int
00277 known_compare (const void *p1, const void *p2)
00278 {
00279   return p1 == p2 ? 0 : strcmp (*(const char *const *) p1,
00280                             *(const char *const *) p2);
00281 }
00282 
00283 
00284 void *
00285 __nss_lookup_function (service_user *ni, const char *fct_name)
00286 {
00287   void **found, *result;
00288 
00289   /* We now modify global data.  Protect it.  */
00290   __libc_lock_lock (lock);
00291 
00292   /* Search the tree of functions previously requested.  Data in the
00293      tree are `known_function' structures, whose first member is a
00294      `const char *', the lookup key.  The search returns a pointer to
00295      the tree node structure; the first member of the is a pointer to
00296      our structure (i.e. what will be a `known_function'); since the
00297      first member of that is the lookup key string, &FCT_NAME is close
00298      enough to a pointer to our structure to use as a lookup key that
00299      will be passed to `known_compare' (above).  */
00300 
00301   found = __tsearch (&fct_name, &ni->known, &known_compare);
00302   if (*found != &fct_name)
00303     /* The search found an existing structure in the tree.  */
00304     result = ((known_function *) *found)->fct_ptr;
00305   else
00306     {
00307       /* This name was not known before.  Now we have a node in the tree
00308         (in the proper sorted position for FCT_NAME) that points to
00309         &FCT_NAME instead of any real `known_function' structure.
00310         Allocate a new structure and fill it in.  */
00311 
00312       known_function *known = malloc (sizeof *known);
00313       if (! known)
00314        {
00315        remove_from_tree:
00316          /* Oops.  We can't instantiate this node properly.
00317             Remove it from the tree.  */
00318          __tdelete (&fct_name, &ni->known, &known_compare);
00319          result = NULL;
00320        }
00321       else
00322        {
00323          /* Point the tree node at this new structure.  */
00324          *found = known;
00325          known->fct_name = fct_name;
00326 
00327          if (ni->library == NULL)
00328            {
00329              /* This service has not yet been used.  Fetch the service
00330                library for it, creating a new one if need be.  If there
00331                is no service table from the file, this static variable
00332                holds the head of the service_library list made from the
00333                default configuration.  */
00334              static name_database default_table;
00335              ni->library = nss_new_service (service_table ?: &default_table,
00336                                         ni->name);
00337              if (ni->library == NULL)
00338               {
00339                 /* This only happens when out of memory.  */
00340                 free (known);
00341                 goto remove_from_tree;
00342               }
00343            }
00344 
00345 #if !defined DO_STATIC_NSS || defined SHARED
00346          if (ni->library->lib_handle == NULL)
00347            {
00348              /* Load the shared library.  */
00349              size_t shlen = (7 + strlen (ni->library->name) + 3
00350                            + strlen (__nss_shlib_revision) + 1);
00351              int saved_errno = errno;
00352              char shlib_name[shlen];
00353 
00354              /* Construct shared object name.  */
00355              __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
00356                                                 "libnss_"),
00357                                        ni->library->name),
00358                               ".so"),
00359                      __nss_shlib_revision);
00360 
00361              ni->library->lib_handle = __libc_dlopen (shlib_name);
00362              if (ni->library->lib_handle == NULL)
00363               {
00364                 /* Failed to load the library.  */
00365                 ni->library->lib_handle = (void *) -1l;
00366                 __set_errno (saved_errno);
00367               }
00368            }
00369 
00370          if (ni->library->lib_handle == (void *) -1l)
00371            /* Library not found => function not found.  */
00372            result = NULL;
00373          else
00374            {
00375              /* Get the desired function.  */
00376              size_t namlen = (5 + strlen (ni->library->name) + 1
00377                             + strlen (fct_name) + 1);
00378              char name[namlen];
00379 
00380              /* Construct the function name.  */
00381              __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
00382                                        ni->library->name),
00383                               "_"),
00384                      fct_name);
00385 
00386              /* Look up the symbol.  */
00387              result = __libc_dlsym (ni->library->lib_handle, name);
00388            }
00389 #else
00390          /* We can't get function address dynamically in static linking. */
00391          {
00392 # define DEFINE_ENT(h,nm)                                            \
00393            { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },               \
00394            { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },                   \
00395            { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
00396 # define DEFINE_GET(h,nm)                                            \
00397            { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
00398 # define DEFINE_GETBY(h,nm,ky)                                              \
00399            { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
00400            static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
00401              {
00402 # include "function.def"
00403               { NULL, NULL }
00404              };
00405            size_t namlen = (5 + strlen (ni->library->name) + 1
00406                           + strlen (fct_name) + 1);
00407            char name[namlen];
00408 
00409            /* Construct the function name.  */
00410            __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
00411                             "_"),
00412                     fct_name);
00413 
00414            result = NULL;
00415            for (tp = &tbl[0]; tp->fname; tp++)
00416              if (strcmp (tp->fname, name) == 0)
00417               {
00418                 result = tp->fp;
00419                 break;
00420               }
00421          }
00422 #endif
00423 
00424          /* Remember function pointer for later calls.  Even if null, we
00425             record it so a second try needn't search the library again.  */
00426          known->fct_ptr = result;
00427        }
00428     }
00429 
00430   /* Remove the lock.  */
00431   __libc_lock_unlock (lock);
00432 
00433   return result;
00434 }
00435 libc_hidden_def (__nss_lookup_function)
00436 
00437 
00438 static name_database *
00439 internal_function
00440 nss_parse_file (const char *fname)
00441 {
00442   FILE *fp;
00443   name_database *result;
00444   name_database_entry *last;
00445   char *line;
00446   size_t len;
00447 
00448   /* Open the configuration file.  */
00449   fp = fopen (fname, "rc");
00450   if (fp == NULL)
00451     return NULL;
00452 
00453   /* No threads use this stream.  */
00454   __fsetlocking (fp, FSETLOCKING_BYCALLER);
00455 
00456   result = (name_database *) malloc (sizeof (name_database));
00457   if (result == NULL)
00458     return NULL;
00459 
00460   result->entry = NULL;
00461   result->library = NULL;
00462   last = NULL;
00463   line = NULL;
00464   len = 0;
00465   do
00466     {
00467       name_database_entry *this;
00468       ssize_t n;
00469 
00470       n = __getline (&line, &len, fp);
00471       if (n < 0)
00472        break;
00473       if (line[n - 1] == '\n')
00474        line[n - 1] = '\0';
00475 
00476       /* Because the file format does not know any form of quoting we
00477         can search forward for the next '#' character and if found
00478         make it terminating the line.  */
00479       *__strchrnul (line, '#') = '\0';
00480 
00481       /* If the line is blank it is ignored.  */
00482       if (line[0] == '\0')
00483        continue;
00484 
00485       /* Each line completely specifies the actions for a database.  */
00486       this = nss_getline (line);
00487       if (this != NULL)
00488        {
00489          if (last != NULL)
00490            last->next = this;
00491          else
00492            result->entry = this;
00493 
00494          last = this;
00495        }
00496     }
00497   while (!feof_unlocked (fp));
00498 
00499   /* Free the buffer.  */
00500   free (line);
00501   /* Close configuration file.  */
00502   fclose (fp);
00503 
00504   return result;
00505 }
00506 
00507 
00508 /* Read the source names:
00509        `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
00510    */
00511 static service_user *
00512 internal_function
00513 nss_parse_service_list (const char *line)
00514 {
00515   service_user *result = NULL, **nextp = &result;
00516 
00517   while (1)
00518     {
00519       service_user *new_service;
00520       const char *name;
00521 
00522       while (isspace (line[0]))
00523        ++line;
00524       if (line[0] == '\0')
00525        /* No source specified.  */
00526        return result;
00527 
00528       /* Read <source> identifier.  */
00529       name = line;
00530       while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
00531        ++line;
00532       if (name == line)
00533        return result;
00534 
00535 
00536       new_service = (service_user *) malloc (sizeof (service_user)
00537                                         + (line - name + 1));
00538       if (new_service == NULL)
00539        return result;
00540 
00541       *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
00542 
00543       /* Set default actions.  */
00544       new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
00545       new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
00546       new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
00547       new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
00548       new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
00549       new_service->library = NULL;
00550       new_service->known = NULL;
00551       new_service->next = NULL;
00552 
00553       while (isspace (line[0]))
00554        ++line;
00555 
00556       if (line[0] == '[')
00557        {
00558          /* Read criterions.  */
00559          do
00560            ++line;
00561          while (line[0] != '\0' && isspace (line[0]));
00562 
00563          do
00564            {
00565              int not;
00566              enum nss_status status;
00567              lookup_actions action;
00568 
00569              /* Grok ! before name to mean all statii but that one.  */
00570              not = line[0] == '!';
00571              if (not)
00572               ++line;
00573 
00574              /* Read status name.  */
00575              name = line;
00576              while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
00577                    && line[0] != ']')
00578               ++line;
00579 
00580              /* Compare with known statii.  */
00581              if (line - name == 7)
00582               {
00583                 if (__strncasecmp (name, "SUCCESS", 7) == 0)
00584                   status = NSS_STATUS_SUCCESS;
00585                 else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
00586                   status = NSS_STATUS_UNAVAIL;
00587                 else
00588                   return result;
00589               }
00590              else if (line - name == 8)
00591               {
00592                 if (__strncasecmp (name, "NOTFOUND", 8) == 0)
00593                   status = NSS_STATUS_NOTFOUND;
00594                 else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
00595                   status = NSS_STATUS_TRYAGAIN;
00596                 else
00597                   return result;
00598               }
00599              else
00600               return result;
00601 
00602              while (isspace (line[0]))
00603               ++line;
00604              if (line[0] != '=')
00605               return result;
00606              do
00607               ++line;
00608              while (isspace (line[0]));
00609 
00610              name = line;
00611              while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
00612                    && line[0] != ']')
00613               ++line;
00614 
00615              if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
00616               action = NSS_ACTION_RETURN;
00617              else if (line - name == 8
00618                      && __strncasecmp (name, "CONTINUE", 8) == 0)
00619               action = NSS_ACTION_CONTINUE;
00620              else
00621               return result;
00622 
00623              if (not)
00624               {
00625                 /* Save the current action setting for this status,
00626                    set them all to the given action, and reset this one.  */
00627                 const lookup_actions save = new_service->actions[2 + status];
00628                 new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
00629                 new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
00630                 new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
00631                 new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
00632                 new_service->actions[2 + status] = save;
00633               }
00634              else
00635               new_service->actions[2 + status] = action;
00636 
00637              /* Skip white spaces.  */
00638              while (isspace (line[0]))
00639               ++line;
00640            }
00641          while (line[0] != ']');
00642 
00643          /* Skip the ']'.  */
00644          ++line;
00645        }
00646 
00647       *nextp = new_service;
00648       nextp = &new_service->next;
00649     }
00650 }
00651 
00652 static name_database_entry *
00653 internal_function
00654 nss_getline (char *line)
00655 {
00656   const char *name;
00657   name_database_entry *result;
00658   size_t len;
00659 
00660   /* Ignore leading white spaces.  ATTENTION: this is different from
00661      what is implemented in Solaris.  The Solaris man page says a line
00662      beginning with a white space character is ignored.  We regard
00663      this as just another misfeature in Solaris.  */
00664   while (isspace (line[0]))
00665     ++line;
00666 
00667   /* Recognize `<database> ":"'.  */
00668   name = line;
00669   while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
00670     ++line;
00671   if (line[0] == '\0' || name == line)
00672     /* Syntax error.  */
00673     return NULL;
00674   *line++ = '\0';
00675 
00676   len = strlen (name) + 1;
00677 
00678   result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
00679   if (result == NULL)
00680     return NULL;
00681 
00682   /* Save the database name.  */
00683   memcpy (result->name, name, len);
00684 
00685   /* Parse the list of services.  */
00686   result->service = nss_parse_service_list (line);
00687 
00688   result->next = NULL;
00689   return result;
00690 }
00691 
00692 
00693 static service_library *
00694 internal_function
00695 nss_new_service (name_database *database, const char *name)
00696 {
00697   service_library **currentp = &database->library;
00698 
00699   while (*currentp != NULL)
00700     {
00701       if (strcmp ((*currentp)->name, name) == 0)
00702        return *currentp;
00703       currentp = &(*currentp)->next;
00704     }
00705 
00706   /* We have to add the new service.  */
00707   *currentp = (service_library *) malloc (sizeof (service_library));
00708   if (*currentp == NULL)
00709     return NULL;
00710 
00711   (*currentp)->name = name;
00712   (*currentp)->lib_handle = NULL;
00713   (*currentp)->next = NULL;
00714 
00715   return *currentp;
00716 }
00717 
00718 
00719 /* Called by nscd and nscd alone.  */
00720 void
00721 __nss_disable_nscd (void)
00722 {
00723   /* Disable all uses of NSCD.  */
00724   __nss_not_use_nscd_passwd = -1;
00725   __nss_not_use_nscd_group = -1;
00726   __nss_not_use_nscd_hosts = -1;
00727   __nss_not_use_nscd_services = -1;
00728 }
00729 
00730 
00731 /* Free all resources if necessary.  */
00732 libc_freeres_fn (free_mem)
00733 {
00734   name_database *top = service_table;
00735   name_database_entry *entry;
00736   service_library *library;
00737 
00738   if (top == NULL)
00739     /* Maybe we have not read the nsswitch.conf file.  */
00740     return;
00741 
00742   /* Don't disturb ongoing other threads (if there are any).  */
00743   service_table = NULL;
00744 
00745   entry = top->entry;
00746   while (entry != NULL)
00747     {
00748       name_database_entry *olde = entry;
00749       service_user *service = entry->service;
00750 
00751       while (service != NULL)
00752        {
00753          service_user *olds = service;
00754 
00755          if (service->known != NULL)
00756            __tdestroy (service->known, free);
00757 
00758          service = service->next;
00759          free (olds);
00760        }
00761 
00762       entry = entry->next;
00763       free (olde);
00764     }
00765 
00766   library = top->library;
00767   while (library != NULL)
00768     {
00769       service_library *oldl = library;
00770 
00771       if (library->lib_handle && library->lib_handle != (void *) -1l)
00772        __libc_dlclose (library->lib_handle);
00773 
00774       library = library->next;
00775       free (oldl);
00776     }
00777 
00778   free (top);
00779 }