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