]> git.ipfire.org Git - thirdparty/glibc.git/blame - nss/nsswitch.c
Stop crash in OOM handling in NSS
[thirdparty/glibc.git] / nss / nsswitch.c
CommitLineData
319b9ad4
UD
1/* Copyright (C) 1996-1999,2001-2007,2009,2010,2011
2 Free Software Foundation, Inc.
2303f5fd
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5f0e6fc7 5
2303f5fd 6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
5f0e6fc7 10
2303f5fd
UD
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
41bdb6e2 14 Lesser General Public License for more details.
5f0e6fc7 15
41bdb6e2
AJ
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
5f0e6fc7
RM
20
21#include <ctype.h>
22#include <dlfcn.h>
a8874ead 23#include <errno.h>
5f0e6fc7 24#include <netdb.h>
5107cf1d 25#include <bits/libc-lock.h>
5f0e6fc7
RM
26#include <search.h>
27#include <stdio.h>
2706ee38 28#include <stdio_ext.h>
5f0e6fc7
RM
29#include <stdlib.h>
30#include <string.h>
5107cf1d 31
7f28638c
AJ
32#include <aliases.h>
33#include <grp.h>
34#include <netinet/ether.h>
35#include <pwd.h>
36#include <shadow.h>
37
b5567b2a 38#if !defined DO_STATIC_NSS || defined SHARED
5107cf1d
UD
39# include <gnu/lib-names.h>
40#endif
5f0e6fc7
RM
41
42#include "nsswitch.h"
ef4d5b32 43#include "../nscd/nscd_proto.h"
319b9ad4 44#include <sysdep.h>
5f0e6fc7
RM
45
46/* Prototypes for the local functions. */
dfd2257a
UD
47static name_database *nss_parse_file (const char *fname) internal_function;
48static name_database_entry *nss_getline (char *line) internal_function;
49static service_user *nss_parse_service_list (const char *line)
50 internal_function;
5f0e6fc7 51static service_library *nss_new_service (name_database *database,
dfd2257a 52 const char *name) internal_function;
5f0e6fc7
RM
53
54
a8874ead
UD
55/* Declare external database variables. */
56#define DEFINE_DATABASE(name) \
6455d255 57 extern service_user *__nss_##name##_database attribute_hidden; \
a8874ead
UD
58 weak_extern (__nss_##name##_database)
59#include "databases.def"
60#undef DEFINE_DATABASE
61
62/* Structure to map database name to variable. */
3d50529d 63static const struct
a8874ead 64{
3d50529d 65 const char name[10];
a8874ead
UD
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};
e7c8359e 74#define ndatabases (sizeof (databases) / sizeof (databases[0]))
a8874ead 75
c3e2f19b
UD
76/* Flags whether custom rules for database is set. */
77bool __nss_database_custom[NSS_DBSIDX_max];
78
a8874ead 79
1e16111c 80__libc_lock_define_initialized (static, lock)
5f0e6fc7 81
b5567b2a 82#if !defined DO_STATIC_NSS || defined SHARED
56552e42 83/* String with revision number of the shared object files. */
1fb05e3d 84static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
5107cf1d 85#endif
5f0e6fc7
RM
86
87/* The root of the whole data base. */
88static name_database *service_table;
89
90
319b9ad4
UD
91/* Nonzero if this is the nscd process. */
92static bool is_nscd;
93/* The callback passed to the init functions when nscd is used. */
94static void (*nscd_init_cb) (size_t, struct traced_file *);
95
96
5f0e6fc7
RM
97/* -1 == database not found
98 0 == database entry pointer stored */
99int
68dbb3a6
UD
100__nss_database_lookup (const char *database, const char *alternate_name,
101 const char *defconfig, service_user **ni)
5f0e6fc7 102{
a8874ead
UD
103 /* Prevent multiple threads to change the service table. */
104 __libc_lock_lock (lock);
bba7bb78 105
a8874ead
UD
106 /* Reconsider database variable in case some other thread called
107 `__nss_configure_lookup' while we waited for the lock. */
108 if (*ni != NULL)
15a83d04
UD
109 {
110 __libc_lock_unlock (lock);
111 return 0;
112 }
a8874ead 113
56552e42
UD
114 /* Are we initialized yet? */
115 if (service_table == NULL)
a8874ead
UD
116 /* Read config file. */
117 service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
5f0e6fc7
RM
118
119 /* Test whether configuration data is available. */
a8874ead 120 if (service_table != NULL)
5f0e6fc7 121 {
a8874ead
UD
122 /* Return first `service_user' entry for DATABASE. */
123 name_database_entry *entry;
c66273aa
RM
124
125 /* XXX Could use some faster mechanism here. But each database is
126 only requested once and so this might not be critical. */
127 for (entry = service_table->entry; entry != NULL; entry = entry->next)
128 if (strcmp (database, entry->name) == 0)
15a83d04 129 *ni = entry->service;
68dbb3a6
UD
130
131 if (*ni == NULL && alternate_name != NULL)
e7fd8a39
UD
132 /* We haven't found an entry so far. Try to find it with the
133 alternative name. */
68dbb3a6
UD
134 for (entry = service_table->entry; entry != NULL; entry = entry->next)
135 if (strcmp (alternate_name, entry->name) == 0)
136 *ni = entry->service;
5f0e6fc7
RM
137 }
138
c66273aa 139 /* No configuration data is available, either because nsswitch.conf
319b9ad4 140 doesn't exist or because it doesn't have a line for this database.
a8874ead
UD
141
142 DEFCONFIG specifies the default service list for this database,
bba7bb78 143 or null to use the most common default. */
15a83d04
UD
144 if (*ni == NULL)
145 *ni = nss_parse_service_list (defconfig
10dc2a90 146 ?: "nis [NOTFOUND=return] files");
a8874ead
UD
147
148 __libc_lock_unlock (lock);
bba7bb78 149
64031225 150 return *ni != NULL ? 0 : -1;
5f0e6fc7 151}
37ba7d66 152libc_hidden_def (__nss_database_lookup)
5f0e6fc7
RM
153
154
155/* -1 == not found
4317f9e1 156 0 == function found
14ea22e9 157 1 == finished */
5f0e6fc7 158int
384ca551
UD
159__nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name,
160 void **fctp)
5f0e6fc7 161{
899d423e 162 *fctp = __nss_lookup_function (*ni, fct_name);
384ca551 163 if (*fctp == NULL && fct2_name != NULL)
0dc6c5e4 164 *fctp = __nss_lookup_function (*ni, fct2_name);
5f0e6fc7
RM
165
166 while (*fctp == NULL
167 && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
168 && (*ni)->next != NULL)
169 {
170 *ni = (*ni)->next;
171
899d423e 172 *fctp = __nss_lookup_function (*ni, fct_name);
384ca551 173 if (*fctp == NULL && fct2_name != NULL)
0dc6c5e4 174 *fctp = __nss_lookup_function (*ni, fct2_name);
5f0e6fc7
RM
175 }
176
14ea22e9 177 return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
5f0e6fc7
RM
178}
179
180
181/* -1 == not found
182 0 == adjusted for next function
183 1 == finished */
184int
384ca551
UD
185__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name,
186 void **fctp, int status, int all_values)
5f0e6fc7
RM
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. */
384ca551
UD
199 if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
200 || status > NSS_STATUS_RETURN, 0))
79dbd981 201 __libc_fatal ("illegal status in __nss_next");
5f0e6fc7
RM
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
899d423e 214 *fctp = __nss_lookup_function (*ni, fct_name);
384ca551
UD
215 if (*fctp == NULL && fct2_name != NULL)
216 *fctp = __nss_lookup_function (*ni, fct2_name);
5f0e6fc7
RM
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}
384ca551
UD
224libc_hidden_def (__nss_next2)
225
226
227int
228attribute_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}
5f0e6fc7
RM
234
235
a8874ead
UD
236int
237__nss_configure_lookup (const char *dbname, const char *service_line)
238{
239 service_user *new_db;
240 size_t cnt;
241
e7c8359e 242 for (cnt = 0; cnt < ndatabases; ++cnt)
df21c858
UD
243 {
244 int cmp = strcmp (dbname, databases[cnt].name);
245 if (cmp == 0)
246 break;
5a97622d 247 if (cmp < 0)
df21c858 248 {
c4029823 249 __set_errno (EINVAL);
df21c858
UD
250 return -1;
251 }
252 }
a8874ead 253
e7c8359e 254 if (cnt == ndatabases)
a8874ead 255 {
c4029823 256 __set_errno (EINVAL);
a8874ead
UD
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. */
c4029823 270 __set_errno (EINVAL);
a8874ead
UD
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;
c3e2f19b 279 __nss_database_custom[cnt] = true;
a8874ead
UD
280
281 __libc_lock_unlock (lock);
282
283 return 0;
284}
285
286
2064087b
RM
287/* Comparison function for searching NI->known tree. */
288static int
289known_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
319b9ad4
UD
296#if !defined DO_STATIC_NSS || defined SHARED
297/* Load library. */
298static int
299nss_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->library->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->library->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->library->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->library->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
899d423e
UD
369void *
370__nss_lookup_function (service_user *ni, const char *fct_name)
5f0e6fc7 371{
dbe31b9a 372 void **found, *result;
5f0e6fc7 373
5f0e6fc7
RM
374 /* We now modify global data. Protect it. */
375 __libc_lock_lock (lock);
376
dbe31b9a
RM
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
701666b7 386 found = __tsearch (&fct_name, &ni->known, &known_compare);
0490345c
JO
387 if (found == NULL)
388 /* This means out-of-memory. */
389 result = NULL;
390 else if (*found != &fct_name)
4ec77f72
UD
391 {
392 /* The search found an existing structure in the tree. */
393 result = ((known_function *) *found)->fct_ptr;
394 PTR_DEMANGLE (result);
395 }
dbe31b9a 396 else
5f0e6fc7 397 {
dbe31b9a
RM
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. */
5f0e6fc7 402
dbe31b9a
RM
403 known_function *known = malloc (sizeof *known);
404 if (! known)
5f0e6fc7 405 {
dbe31b9a
RM
406 remove_from_tree:
407 /* Oops. We can't instantiate this node properly.
408 Remove it from the tree. */
701666b7 409 __tdelete (&fct_name, &ni->known, &known_compare);
054c0457 410 free (known);
dbe31b9a 411 result = NULL;
5f0e6fc7 412 }
dbe31b9a 413 else
5f0e6fc7 414 {
dbe31b9a
RM
415 /* Point the tree node at this new structure. */
416 *found = known;
417 known->fct_name = fct_name;
418
b5567b2a 419#if !defined DO_STATIC_NSS || defined SHARED
319b9ad4
UD
420 /* Load the appropriate library. */
421 if (nss_load_library (ni) != 0)
054c0457
UD
422 /* This only happens when out of memory. */
423 goto remove_from_tree;
dbe31b9a 424
8a523922 425 if (ni->library->lib_handle == (void *) -1l)
dbe31b9a
RM
426 /* Library not found => function not found. */
427 result = NULL;
428 else
429 {
b3fc5f84 430 /* Get the desired function. */
dbe31b9a
RM
431 size_t namlen = (5 + strlen (ni->library->name) + 1
432 + strlen (fct_name) + 1);
b3fc5f84 433 char name[namlen];
dbe31b9a
RM
434
435 /* Construct the function name. */
b3fc5f84 436 __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
dbe31b9a
RM
437 ni->library->name),
438 "_"),
439 fct_name);
440
441 /* Look up the symbol. */
b3fc5f84 442 result = __libc_dlsym (ni->library->lib_handle, name);
dbe31b9a 443 }
5107cf1d
UD
444#else
445 /* We can't get function address dynamically in static linking. */
446 {
5107cf1d 447# define DEFINE_ENT(h,nm) \
1522c368
UD
448 { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \
449 { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \
5107cf1d
UD
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 {
1522c368 457# include "function.def"
5107cf1d
UD
458 { NULL, NULL }
459 };
460 size_t namlen = (5 + strlen (ni->library->name) + 1
461 + strlen (fct_name) + 1);
462 char name[namlen];
463
464 /* Construct the function name. */
465 __stpcpy (__stpcpy (__stpcpy (name, ni->library->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
dbe31b9a
RM
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;
4ec77f72 482 PTR_MANGLE (known->fct_ptr);
5f0e6fc7 483 }
5f0e6fc7
RM
484 }
485
5f0e6fc7
RM
486 /* Remove the lock. */
487 __libc_lock_unlock (lock);
488
489 return result;
490}
5556fc6a 491libc_hidden_def (__nss_lookup_function)
5f0e6fc7
RM
492
493
5f0e6fc7 494static name_database *
dfd2257a 495internal_function
5f0e6fc7
RM
496nss_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. */
ee8449f7 505 fp = fopen (fname, "rc");
5f0e6fc7
RM
506 if (fp == NULL)
507 return NULL;
508
2706ee38
UD
509 /* No threads use this stream. */
510 __fsetlocking (fp, FSETLOCKING_BYCALLER);
511
5f0e6fc7
RM
512 result = (name_database *) malloc (sizeof (name_database));
513 if (result == NULL)
319b9ad4
UD
514 {
515 fclose (fp);
516 return NULL;
517 }
5f0e6fc7
RM
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;
5f0e6fc7 528
bba7bb78 529 n = __getline (&line, &len, fp);
5f0e6fc7
RM
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. */
c4563d2d 538 *__strchrnul (line, '#') = '\0';
5f0e6fc7
RM
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 }
71412a8c 556 while (!feof_unlocked (fp));
5f0e6fc7
RM
557
558 /* Free the buffer. */
559 free (line);
560 /* Close configuration file. */
561 fclose (fp);
562
5f0e6fc7
RM
563 return result;
564}
565
566
a8874ead
UD
567/* Read the source names:
568 `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
569 */
bba7bb78 570static service_user *
dfd2257a 571internal_function
bba7bb78 572nss_parse_service_list (const char *line)
5f0e6fc7 573{
bba7bb78 574 service_user *result = NULL, **nextp = &result;
5f0e6fc7 575
5f0e6fc7
RM
576 while (1)
577 {
578 service_user *new_service;
3776d592 579 const char *name;
5f0e6fc7
RM
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
1a989e00
UD
595 new_service = (service_user *) malloc (sizeof (service_user)
596 + (line - name + 1));
5f0e6fc7
RM
597 if (new_service == NULL)
598 return result;
5f0e6fc7 599
1a989e00 600 *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
5f0e6fc7
RM
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;
a68b0d31 607 new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
5f0e6fc7
RM
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 {
5f0e6fc7
RM
617 /* Read criterions. */
618 do
619 ++line;
620 while (line[0] != '\0' && isspace (line[0]));
621
622 do
623 {
bba7bb78
RM
624 int not;
625 enum nss_status status;
626 lookup_actions action;
627
628 /* Grok ! before name to mean all statii but that one. */
6796bc80
UD
629 not = line[0] == '!';
630 if (not)
bba7bb78
RM
631 ++line;
632
5f0e6fc7
RM
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 {
bba7bb78 642 if (__strncasecmp (name, "SUCCESS", 7) == 0)
5f0e6fc7 643 status = NSS_STATUS_SUCCESS;
bba7bb78 644 else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
5f0e6fc7
RM
645 status = NSS_STATUS_UNAVAIL;
646 else
647 return result;
648 }
649 else if (line - name == 8)
650 {
bba7bb78 651 if (__strncasecmp (name, "NOTFOUND", 8) == 0)
5f0e6fc7 652 status = NSS_STATUS_NOTFOUND;
bba7bb78 653 else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
5f0e6fc7
RM
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
bba7bb78
RM
674 if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
675 action = NSS_ACTION_RETURN;
5f0e6fc7 676 else if (line - name == 8
bba7bb78
RM
677 && __strncasecmp (name, "CONTINUE", 8) == 0)
678 action = NSS_ACTION_CONTINUE;
5f0e6fc7
RM
679 else
680 return result;
681
bba7bb78
RM
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. */
5f0e6fc7
RM
697 while (isspace (line[0]))
698 ++line;
699 }
700 while (line[0] != ']');
701
702 /* Skip the ']'. */
703 ++line;
704 }
705
bba7bb78
RM
706 *nextp = new_service;
707 nextp = &new_service->next;
5f0e6fc7 708 }
bba7bb78
RM
709}
710
711static name_database_entry *
dfd2257a 712internal_function
bba7bb78
RM
713nss_getline (char *line)
714{
715 const char *name;
716 name_database_entry *result;
1a989e00 717 size_t len;
bba7bb78
RM
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
1a989e00
UD
735 len = strlen (name) + 1;
736
737 result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
bba7bb78
RM
738 if (result == NULL)
739 return NULL;
740
741 /* Save the database name. */
1a989e00 742 memcpy (result->name, name, len);
bba7bb78
RM
743
744 /* Parse the list of services. */
745 result->service = nss_parse_service_list (line);
746
747 result->next = NULL;
748 return result;
5f0e6fc7
RM
749}
750
751
752static service_library *
dfd2257a 753internal_function
5f0e6fc7
RM
754nss_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}
d60d215c
UD
776
777
319b9ad4
UD
778#ifdef SHARED
779/* Load all libraries for the service. */
780static void
781nss_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
ef4d5b32
UD
794/* Called by nscd and nscd alone. */
795void
319b9ad4 796__nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
ef4d5b32 797{
319b9ad4
UD
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
ef4d5b32
UD
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;
b21fa963 814 __nss_not_use_nscd_services = -1;
ef4d5b32 815}
319b9ad4 816#endif
ef4d5b32
UD
817
818
d60d215c 819/* Free all resources if necessary. */
c877418f 820libc_freeres_fn (free_mem)
d60d215c
UD
821{
822 name_database *top = service_table;
823 name_database_entry *entry;
824 service_library *library;
825
826 if (top == NULL)
827 /* Maybe we have not read the nsswitch.conf file. */
828 return;
829
830 /* Don't disturb ongoing other threads (if there are any). */
831 service_table = NULL;
832
833 entry = top->entry;
834 while (entry != NULL)
835 {
836 name_database_entry *olde = entry;
837 service_user *service = entry->service;
838
839 while (service != NULL)
840 {
841 service_user *olds = service;
842
843 if (service->known != NULL)
1483b753 844 __tdestroy (service->known, free);
d60d215c
UD
845
846 service = service->next;
847 free (olds);
848 }
849
850 entry = entry->next;
851 free (olde);
852 }
853
854 library = top->library;
855 while (library != NULL)
856 {
857 service_library *oldl = library;
858
0ab7f77e
RM
859 if (library->lib_handle && library->lib_handle != (void *) -1l)
860 __libc_dlclose (library->lib_handle);
d60d215c
UD
861
862 library = library->next;
863 free (oldl);
864 }
865
866 free (top);
867}