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