53ff5f8f714d72c267847ede662b99aa6507034d
[jlayton/glibc.git] / nss / nsswitch.c
1 /* Copyright (C) 1996-2012
2    Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <ctype.h>
21 #include <dlfcn.h>
22 #include <errno.h>
23 #include <netdb.h>
24 #include <bits/libc-lock.h>
25 #include <search.h>
26 #include <stdio.h>
27 #include <stdio_ext.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <aliases.h>
32 #include <grp.h>
33 #include <netinet/ether.h>
34 #include <pwd.h>
35 #include <shadow.h>
36
37 #if !defined DO_STATIC_NSS || defined SHARED
38 # include <gnu/lib-names.h>
39 #endif
40
41 #include "nsswitch.h"
42 #include "../nscd/nscd_proto.h"
43 #include <sysdep.h>
44
45 /* Prototypes for the local functions.  */
46 static name_database *nss_parse_file (const char *fname) internal_function;
47 static name_database_entry *nss_getline (char *line) internal_function;
48 static service_user *nss_parse_service_list (const char *line)
49      internal_function;
50 static service_library *nss_new_service (name_database *database,
51                                          const char *name) internal_function;
52
53
54 /* Declare external database variables.  */
55 #define DEFINE_DATABASE(name)                                                 \
56   extern service_user *__nss_##name##_database attribute_hidden;              \
57   weak_extern (__nss_##name##_database)
58 #include "databases.def"
59 #undef DEFINE_DATABASE
60
61 /* Structure to map database name to variable.  */
62 static const struct
63 {
64   const char name[10];
65   service_user **dbp;
66 } databases[] =
67 {
68 #define DEFINE_DATABASE(name)                                                 \
69   { #name, &__nss_##name##_database },
70 #include "databases.def"
71 #undef DEFINE_DATABASE
72 };
73 #define ndatabases (sizeof (databases) / sizeof (databases[0]))
74
75 /* Flags whether custom rules for database is set.  */
76 bool __nss_database_custom[NSS_DBSIDX_max];
77
78
79 __libc_lock_define_initialized (static, lock)
80
81 #if !defined DO_STATIC_NSS || defined SHARED
82 /* String with revision number of the shared object files.  */
83 static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
84 #endif
85
86 /* The root of the whole data base.  */
87 static name_database *service_table;
88
89
90 /* Nonzero if this is the nscd process.  */
91 static bool is_nscd;
92 /* The callback passed to the init functions when nscd is used.  */
93 static void (*nscd_init_cb) (size_t, struct traced_file *);
94
95
96 /* -1 == database not found
97     0 == database entry pointer stored */
98 int
99 __nss_database_lookup (const char *database, const char *alternate_name,
100                        const char *defconfig, service_user **ni)
101 {
102   /* Prevent multiple threads to change the service table.  */
103   __libc_lock_lock (lock);
104
105   /* Reconsider database variable in case some other thread called
106      `__nss_configure_lookup' while we waited for the lock.  */
107   if (*ni != NULL)
108     {
109       __libc_lock_unlock (lock);
110       return 0;
111     }
112
113   /* Are we initialized yet?  */
114   if (service_table == NULL)
115     /* Read config file.  */
116     service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
117
118   /* Test whether configuration data is available.  */
119   if (service_table != NULL)
120     {
121       /* Return first `service_user' entry for DATABASE.  */
122       name_database_entry *entry;
123
124       /* XXX Could use some faster mechanism here.  But each database is
125          only requested once and so this might not be critical.  */
126       for (entry = service_table->entry; entry != NULL; entry = entry->next)
127         if (strcmp (database, entry->name) == 0)
128           *ni = entry->service;
129
130       if (*ni == NULL && alternate_name != NULL)
131         /* We haven't found an entry so far.  Try to find it with the
132            alternative name.  */
133         for (entry = service_table->entry; entry != NULL; entry = entry->next)
134           if (strcmp (alternate_name, entry->name) == 0)
135             *ni = entry->service;
136     }
137
138   /* No configuration data is available, either because nsswitch.conf
139      doesn't exist or because it doesn't have a line for this database.
140
141      DEFCONFIG specifies the default service list for this database,
142      or null to use the most common default.  */
143   if (*ni == NULL)
144     *ni = nss_parse_service_list (defconfig
145                                   ?: "nis [NOTFOUND=return] files");
146
147   __libc_lock_unlock (lock);
148
149   return *ni != NULL ? 0 : -1;
150 }
151 libc_hidden_def (__nss_database_lookup)
152
153
154 /* -1 == not found
155     0 == function found
156     1 == finished */
157 int
158 __nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name,
159               void **fctp)
160 {
161   *fctp = __nss_lookup_function (*ni, fct_name);
162   if (*fctp == NULL && fct2_name != NULL)
163     *fctp = __nss_lookup_function (*ni, fct2_name);
164
165   while (*fctp == NULL
166          && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
167          && (*ni)->next != NULL)
168     {
169       *ni = (*ni)->next;
170
171       *fctp = __nss_lookup_function (*ni, fct_name);
172       if (*fctp == NULL && fct2_name != NULL)
173         *fctp = __nss_lookup_function (*ni, fct2_name);
174     }
175
176   return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
177 }
178 libc_hidden_def (__nss_lookup)
179
180
181 /* -1 == not found
182     0 == adjusted for next function
183     1 == finished */
184 int
185 __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name,
186              void **fctp, int status, int all_values)
187 {
188   if (all_values)
189     {
190       if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
191           && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
192           && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
193           && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
194         return 1;
195     }
196   else
197     {
198       /* This is really only for debugging.  */
199       if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
200                             || status > NSS_STATUS_RETURN, 0))
201          __libc_fatal ("illegal status in __nss_next");
202
203        if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
204          return 1;
205     }
206
207   if ((*ni)->next == NULL)
208     return -1;
209
210   do
211     {
212       *ni = (*ni)->next;
213
214       *fctp = __nss_lookup_function (*ni, fct_name);
215       if (*fctp == NULL && fct2_name != NULL)
216         *fctp = __nss_lookup_function (*ni, fct2_name);
217     }
218   while (*fctp == NULL
219          && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
220          && (*ni)->next != NULL);
221
222   return *fctp != NULL ? 0 : -1;
223 }
224 libc_hidden_def (__nss_next2)
225
226
227 int
228 attribute_compat_text_section
229 __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
230             int all_values)
231 {
232   return __nss_next2 (ni, fct_name, NULL, fctp, status, all_values);
233 }
234
235
236 int
237 __nss_configure_lookup (const char *dbname, const char *service_line)
238 {
239   service_user *new_db;
240   size_t cnt;
241
242   for (cnt = 0; cnt < ndatabases; ++cnt)
243     {
244       int cmp = strcmp (dbname, databases[cnt].name);
245       if (cmp == 0)
246         break;
247       if (cmp < 0)
248         {
249           __set_errno (EINVAL);
250           return -1;
251         }
252     }
253
254   if (cnt == ndatabases)
255     {
256       __set_errno (EINVAL);
257       return -1;
258     }
259
260   /* Test whether it is really used.  */
261   if (databases[cnt].dbp == NULL)
262     /* Nothing to do, but we could do.  */
263     return 0;
264
265   /* Try to generate new data.  */
266   new_db = nss_parse_service_list (service_line);
267   if (new_db == NULL)
268     {
269       /* Illegal service specification.  */
270       __set_errno (EINVAL);
271       return -1;
272     }
273
274   /* Prevent multiple threads to change the service table.  */
275   __libc_lock_lock (lock);
276
277   /* Install new rules.  */
278   *databases[cnt].dbp = new_db;
279   __nss_database_custom[cnt] = true;
280
281   __libc_lock_unlock (lock);
282
283   return 0;
284 }
285
286
287 /* Comparison function for searching NI->known tree.  */
288 static int
289 known_compare (const void *p1, const void *p2)
290 {
291   return p1 == p2 ? 0 : strcmp (*(const char *const *) p1,
292                                 *(const char *const *) p2);
293 }
294
295
296 #if !defined DO_STATIC_NSS || defined SHARED
297 /* Load library.  */
298 static int
299 nss_load_library (service_user *ni)
300 {
301   if (ni->library == NULL)
302     {
303       /* This service has not yet been used.  Fetch the service
304          library for it, creating a new one if need be.  If there
305          is no service table from the file, this static variable
306          holds the head of the service_library list made from the
307          default configuration.  */
308       static name_database default_table;
309       ni->library = nss_new_service (service_table ?: &default_table,
310                                      ni->name);
311       if (ni->library == NULL)
312         return -1;
313     }
314
315   if (ni->library->lib_handle == NULL)
316     {
317       /* Load the shared library.  */
318       size_t shlen = (7 + strlen (ni->name) + 3
319                       + strlen (__nss_shlib_revision) + 1);
320       int saved_errno = errno;
321       char shlib_name[shlen];
322
323       /* Construct shared object name.  */
324       __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
325                                               "libnss_"),
326                                     ni->name),
327                           ".so"),
328                 __nss_shlib_revision);
329
330       ni->library->lib_handle = __libc_dlopen (shlib_name);
331       if (ni->library->lib_handle == NULL)
332         {
333           /* Failed to load the library.  */
334           ni->library->lib_handle = (void *) -1l;
335           __set_errno (saved_errno);
336         }
337       else if (is_nscd)
338         {
339           /* Call the init function when nscd is used.  */
340           size_t initlen = (5 + strlen (ni->name)
341                             + strlen ("_init") + 1);
342           char init_name[initlen];
343
344           /* Construct the init function name.  */
345           __stpcpy (__stpcpy (__stpcpy (init_name,
346                                         "_nss_"),
347                               ni->name),
348                     "_init");
349
350           /* Find the optional init function.  */
351           void (*ifct) (void (*) (size_t, struct traced_file *))
352             = __libc_dlsym (ni->library->lib_handle, init_name);
353           if (ifct != NULL)
354             {
355               void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
356 # ifdef PTR_DEMANGLE
357               PTR_DEMANGLE (cb);
358 # endif
359               ifct (cb);
360             }
361         }
362     }
363
364   return 0;
365 }
366 #endif
367
368
369 void *
370 __nss_lookup_function (service_user *ni, const char *fct_name)
371 {
372   void **found, *result;
373
374   /* We now modify global data.  Protect it.  */
375   __libc_lock_lock (lock);
376
377   /* Search the tree of functions previously requested.  Data in the
378      tree are `known_function' structures, whose first member is a
379      `const char *', the lookup key.  The search returns a pointer to
380      the tree node structure; the first member of the is a pointer to
381      our structure (i.e. what will be a `known_function'); since the
382      first member of that is the lookup key string, &FCT_NAME is close
383      enough to a pointer to our structure to use as a lookup key that
384      will be passed to `known_compare' (above).  */
385
386   found = __tsearch (&fct_name, &ni->known, &known_compare);
387   if (found == NULL)
388     /* This means out-of-memory.  */
389     result = NULL;
390   else if (*found != &fct_name)
391     {
392       /* The search found an existing structure in the tree.  */
393       result = ((known_function *) *found)->fct_ptr;
394       PTR_DEMANGLE (result);
395     }
396   else
397     {
398       /* This name was not known before.  Now we have a node in the tree
399          (in the proper sorted position for FCT_NAME) that points to
400          &FCT_NAME instead of any real `known_function' structure.
401          Allocate a new structure and fill it in.  */
402
403       known_function *known = malloc (sizeof *known);
404       if (! known)
405         {
406         remove_from_tree:
407           /* Oops.  We can't instantiate this node properly.
408              Remove it from the tree.  */
409           __tdelete (&fct_name, &ni->known, &known_compare);
410           free (known);
411           result = NULL;
412         }
413       else
414         {
415           /* Point the tree node at this new structure.  */
416           *found = known;
417           known->fct_name = fct_name;
418
419 #if !defined DO_STATIC_NSS || defined SHARED
420           /* Load the appropriate library.  */
421           if (nss_load_library (ni) != 0)
422             /* This only happens when out of memory.  */
423             goto remove_from_tree;
424
425           if (ni->library->lib_handle == (void *) -1l)
426             /* Library not found => function not found.  */
427             result = NULL;
428           else
429             {
430               /* Get the desired function.  */
431               size_t namlen = (5 + strlen (ni->name) + 1
432                                + strlen (fct_name) + 1);
433               char name[namlen];
434
435               /* Construct the function name.  */
436               __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
437                                             ni->name),
438                                   "_"),
439                         fct_name);
440
441               /* Look up the symbol.  */
442               result = __libc_dlsym (ni->library->lib_handle, name);
443             }
444 #else
445           /* We can't get function address dynamically in static linking. */
446           {
447 # define DEFINE_ENT(h,nm)                                                     \
448             { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },                \
449             { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },                    \
450             { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
451 # define DEFINE_GET(h,nm)                                                     \
452             { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
453 # define DEFINE_GETBY(h,nm,ky)                                                \
454             { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
455             static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
456               {
457 # include "function.def"
458                 { NULL, NULL }
459               };
460             size_t namlen = (5 + strlen (ni->name) + 1
461                              + strlen (fct_name) + 1);
462             char name[namlen];
463
464             /* Construct the function name.  */
465             __stpcpy (__stpcpy (__stpcpy (name, ni->name),
466                                 "_"),
467                       fct_name);
468
469             result = NULL;
470             for (tp = &tbl[0]; tp->fname; tp++)
471               if (strcmp (tp->fname, name) == 0)
472                 {
473                   result = tp->fp;
474                   break;
475                 }
476           }
477 #endif
478
479           /* Remember function pointer for later calls.  Even if null, we
480              record it so a second try needn't search the library again.  */
481           known->fct_ptr = result;
482           PTR_MANGLE (known->fct_ptr);
483         }
484     }
485
486   /* Remove the lock.  */
487   __libc_lock_unlock (lock);
488
489   return result;
490 }
491 libc_hidden_def (__nss_lookup_function)
492
493
494 static name_database *
495 internal_function
496 nss_parse_file (const char *fname)
497 {
498   FILE *fp;
499   name_database *result;
500   name_database_entry *last;
501   char *line;
502   size_t len;
503
504   /* Open the configuration file.  */
505   fp = fopen (fname, "rce");
506   if (fp == NULL)
507     return NULL;
508
509   /* No threads use this stream.  */
510   __fsetlocking (fp, FSETLOCKING_BYCALLER);
511
512   result = (name_database *) malloc (sizeof (name_database));
513   if (result == NULL)
514     {
515       fclose (fp);
516       return NULL;
517     }
518
519   result->entry = NULL;
520   result->library = NULL;
521   last = NULL;
522   line = NULL;
523   len = 0;
524   do
525     {
526       name_database_entry *this;
527       ssize_t n;
528
529       n = __getline (&line, &len, fp);
530       if (n < 0)
531         break;
532       if (line[n - 1] == '\n')
533         line[n - 1] = '\0';
534
535       /* Because the file format does not know any form of quoting we
536          can search forward for the next '#' character and if found
537          make it terminating the line.  */
538       *__strchrnul (line, '#') = '\0';
539
540       /* If the line is blank it is ignored.  */
541       if (line[0] == '\0')
542         continue;
543
544       /* Each line completely specifies the actions for a database.  */
545       this = nss_getline (line);
546       if (this != NULL)
547         {
548           if (last != NULL)
549             last->next = this;
550           else
551             result->entry = this;
552
553           last = this;
554         }
555     }
556   while (!feof_unlocked (fp));
557
558   /* Free the buffer.  */
559   free (line);
560   /* Close configuration file.  */
561   fclose (fp);
562
563   return result;
564 }
565
566
567 /* Read the source names:
568         `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
569    */
570 static service_user *
571 internal_function
572 nss_parse_service_list (const char *line)
573 {
574   service_user *result = NULL, **nextp = &result;
575
576   while (1)
577     {
578       service_user *new_service;
579       const char *name;
580
581       while (isspace (line[0]))
582         ++line;
583       if (line[0] == '\0')
584         /* No source specified.  */
585         return result;
586
587       /* Read <source> identifier.  */
588       name = line;
589       while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
590         ++line;
591       if (name == line)
592         return result;
593
594
595       new_service = (service_user *) malloc (sizeof (service_user)
596                                              + (line - name + 1));
597       if (new_service == NULL)
598         return result;
599
600       *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
601
602       /* Set default actions.  */
603       new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
604       new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
605       new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
606       new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
607       new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
608       new_service->library = NULL;
609       new_service->known = NULL;
610       new_service->next = NULL;
611
612       while (isspace (line[0]))
613         ++line;
614
615       if (line[0] == '[')
616         {
617           /* Read criterions.  */
618           do
619             ++line;
620           while (line[0] != '\0' && isspace (line[0]));
621
622           do
623             {
624               int not;
625               enum nss_status status;
626               lookup_actions action;
627
628               /* Grok ! before name to mean all statii but that one.  */
629               not = line[0] == '!';
630               if (not)
631                 ++line;
632
633               /* Read status name.  */
634               name = line;
635               while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
636                      && line[0] != ']')
637                 ++line;
638
639               /* Compare with known statii.  */
640               if (line - name == 7)
641                 {
642                   if (__strncasecmp (name, "SUCCESS", 7) == 0)
643                     status = NSS_STATUS_SUCCESS;
644                   else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
645                     status = NSS_STATUS_UNAVAIL;
646                   else
647                     return result;
648                 }
649               else if (line - name == 8)
650                 {
651                   if (__strncasecmp (name, "NOTFOUND", 8) == 0)
652                     status = NSS_STATUS_NOTFOUND;
653                   else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
654                     status = NSS_STATUS_TRYAGAIN;
655                   else
656                     return result;
657                 }
658               else
659                 return result;
660
661               while (isspace (line[0]))
662                 ++line;
663               if (line[0] != '=')
664                 return result;
665               do
666                 ++line;
667               while (isspace (line[0]));
668
669               name = line;
670               while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
671                      && line[0] != ']')
672                 ++line;
673
674               if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
675                 action = NSS_ACTION_RETURN;
676               else if (line - name == 8
677                        && __strncasecmp (name, "CONTINUE", 8) == 0)
678                 action = NSS_ACTION_CONTINUE;
679               else
680                 return result;
681
682               if (not)
683                 {
684                   /* Save the current action setting for this status,
685                      set them all to the given action, and reset this one.  */
686                   const lookup_actions save = new_service->actions[2 + status];
687                   new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
688                   new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
689                   new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
690                   new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
691                   new_service->actions[2 + status] = save;
692                 }
693               else
694                 new_service->actions[2 + status] = action;
695
696               /* Skip white spaces.  */
697               while (isspace (line[0]))
698                 ++line;
699             }
700           while (line[0] != ']');
701
702           /* Skip the ']'.  */
703           ++line;
704         }
705
706       *nextp = new_service;
707       nextp = &new_service->next;
708     }
709 }
710
711 static name_database_entry *
712 internal_function
713 nss_getline (char *line)
714 {
715   const char *name;
716   name_database_entry *result;
717   size_t len;
718
719   /* Ignore leading white spaces.  ATTENTION: this is different from
720      what is implemented in Solaris.  The Solaris man page says a line
721      beginning with a white space character is ignored.  We regard
722      this as just another misfeature in Solaris.  */
723   while (isspace (line[0]))
724     ++line;
725
726   /* Recognize `<database> ":"'.  */
727   name = line;
728   while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
729     ++line;
730   if (line[0] == '\0' || name == line)
731     /* Syntax error.  */
732     return NULL;
733   *line++ = '\0';
734
735   len = strlen (name) + 1;
736
737   result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
738   if (result == NULL)
739     return NULL;
740
741   /* Save the database name.  */
742   memcpy (result->name, name, len);
743
744   /* Parse the list of services.  */
745   result->service = nss_parse_service_list (line);
746
747   result->next = NULL;
748   return result;
749 }
750
751
752 static service_library *
753 internal_function
754 nss_new_service (name_database *database, const char *name)
755 {
756   service_library **currentp = &database->library;
757
758   while (*currentp != NULL)
759     {
760       if (strcmp ((*currentp)->name, name) == 0)
761         return *currentp;
762       currentp = &(*currentp)->next;
763     }
764
765   /* We have to add the new service.  */
766   *currentp = (service_library *) malloc (sizeof (service_library));
767   if (*currentp == NULL)
768     return NULL;
769
770   (*currentp)->name = name;
771   (*currentp)->lib_handle = NULL;
772   (*currentp)->next = NULL;
773
774   return *currentp;
775 }
776
777
778 #ifdef SHARED
779 /* Load all libraries for the service.  */
780 static void
781 nss_load_all_libraries (const char *service, const char *def)
782 {
783   service_user *ni = NULL;
784
785   if (__nss_database_lookup (service, NULL, def, &ni) == 0)
786     while (ni != NULL)
787       {
788         nss_load_library (ni);
789         ni = ni->next;
790       }
791 }
792
793
794 /* Called by nscd and nscd alone.  */
795 void
796 __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
797 {
798 # ifdef PTR_MANGLE
799   PTR_MANGLE (cb);
800 # endif
801   nscd_init_cb = cb;
802   is_nscd = true;
803
804   /* Find all the relevant modules so that the init functions are called.  */
805   nss_load_all_libraries ("passwd", "compat [NOTFOUND=return] files");
806   nss_load_all_libraries ("group", "compat [NOTFOUND=return] files");
807   nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files");
808   nss_load_all_libraries ("services", NULL);
809
810   /* Disable all uses of NSCD.  */
811   __nss_not_use_nscd_passwd = -1;
812   __nss_not_use_nscd_group = -1;
813   __nss_not_use_nscd_hosts = -1;
814   __nss_not_use_nscd_services = -1;
815   __nss_not_use_nscd_netgroup = -1;
816 }
817 #endif
818
819
820 /* Free all resources if necessary.  */
821 libc_freeres_fn (free_mem)
822 {
823   name_database *top = service_table;
824   name_database_entry *entry;
825   service_library *library;
826
827   if (top == NULL)
828     /* Maybe we have not read the nsswitch.conf file.  */
829     return;
830
831   /* Don't disturb ongoing other threads (if there are any).  */
832   service_table = NULL;
833
834   entry = top->entry;
835   while (entry != NULL)
836     {
837       name_database_entry *olde = entry;
838       service_user *service = entry->service;
839
840       while (service != NULL)
841         {
842           service_user *olds = service;
843
844           if (service->known != NULL)
845             __tdestroy (service->known, free);
846
847           service = service->next;
848           free (olds);
849         }
850
851       entry = entry->next;
852       free (olde);
853     }
854
855   library = top->library;
856   while (library != NULL)
857     {
858       service_library *oldl = library;
859
860       if (library->lib_handle && library->lib_handle != (void *) -1l)
861         __libc_dlclose (library->lib_handle);
862
863       library = library->next;
864       free (oldl);
865     }
866
867   free (top);
868 }