1 /* Copyright (C) 1996,1997,1998,1999,2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 #include <bits/libc-lock.h>
32 #include <netinet/ether.h>
36 #if !defined DO_STATIC_NSS || defined SHARED
37 # include <gnu/lib-names.h>
42 /* Prototypes for the local functions. */
43 static name_database
*nss_parse_file (const char *fname
) internal_function
;
44 static name_database_entry
*nss_getline (char *line
) internal_function
;
45 static service_user
*nss_parse_service_list (const char *line
)
47 static service_library
*nss_new_service (name_database
*database
,
48 const char *name
) internal_function
;
51 /* Declare external database variables. */
52 #define DEFINE_DATABASE(name) \
53 extern service_user *__nss_##name##_database; \
54 weak_extern (__nss_##name##_database)
55 #include "databases.def"
56 #undef DEFINE_DATABASE
58 /* Structure to map database name to variable. */
65 #define DEFINE_DATABASE(name) \
66 { #name, &__nss_##name##_database },
67 #include "databases.def"
68 #undef DEFINE_DATABASE
72 __libc_lock_define_initialized (static, lock
)
74 #if !defined DO_STATIC_NSS || defined SHARED
75 /* String with revision number of the shared object files. */
76 static const char *const __nss_shlib_revision
= LIBNSS_FILES_SO
+ 15;
79 /* The root of the whole data base. */
80 static name_database
*service_table
;
83 /* -1 == database not found
84 0 == database entry pointer stored */
86 __nss_database_lookup (const char *database
, const char *alternate_name
,
87 const char *defconfig
, service_user
**ni
)
89 /* Prevent multiple threads to change the service table. */
90 __libc_lock_lock (lock
);
92 /* Reconsider database variable in case some other thread called
93 `__nss_configure_lookup' while we waited for the lock. */
96 __libc_lock_unlock (lock
);
100 /* Are we initialized yet? */
101 if (service_table
== NULL
)
102 /* Read config file. */
103 service_table
= nss_parse_file (_PATH_NSSWITCH_CONF
);
105 /* Test whether configuration data is available. */
106 if (service_table
!= NULL
)
108 /* Return first `service_user' entry for DATABASE. */
109 name_database_entry
*entry
;
111 /* XXX Could use some faster mechanism here. But each database is
112 only requested once and so this might not be critical. */
113 for (entry
= service_table
->entry
; entry
!= NULL
; entry
= entry
->next
)
114 if (strcmp (database
, entry
->name
) == 0)
115 *ni
= entry
->service
;
117 if (*ni
== NULL
&& alternate_name
!= NULL
)
118 /* We haven't found an entry so far. Try to find it with the
120 for (entry
= service_table
->entry
; entry
!= NULL
; entry
= entry
->next
)
121 if (strcmp (alternate_name
, entry
->name
) == 0)
122 *ni
= entry
->service
;
125 /* No configuration data is available, either because nsswitch.conf
126 doesn't exist or because it doesn't has a line for this database.
128 DEFCONFIG specifies the default service list for this database,
129 or null to use the most common default. */
131 *ni
= nss_parse_service_list (defconfig
132 ?: "nis [NOTFOUND=return] files");
134 __libc_lock_unlock (lock
);
144 __nss_lookup (service_user
**ni
, const char *fct_name
, void **fctp
)
146 *fctp
= __nss_lookup_function (*ni
, fct_name
);
149 && nss_next_action (*ni
, NSS_STATUS_UNAVAIL
) == NSS_ACTION_CONTINUE
150 && (*ni
)->next
!= NULL
)
154 *fctp
= __nss_lookup_function (*ni
, fct_name
);
157 return *fctp
!= NULL
? 0 : (*ni
)->next
== NULL
? 1 : -1;
162 0 == adjusted for next function
165 __nss_next (service_user
**ni
, const char *fct_name
, void **fctp
, int status
,
170 if (nss_next_action (*ni
, NSS_STATUS_TRYAGAIN
) == NSS_ACTION_RETURN
171 && nss_next_action (*ni
, NSS_STATUS_UNAVAIL
) == NSS_ACTION_RETURN
172 && nss_next_action (*ni
, NSS_STATUS_NOTFOUND
) == NSS_ACTION_RETURN
173 && nss_next_action (*ni
, NSS_STATUS_SUCCESS
) == NSS_ACTION_RETURN
)
178 /* This is really only for debugging. */
179 if (NSS_STATUS_TRYAGAIN
> status
|| status
> NSS_STATUS_RETURN
)
180 __libc_fatal ("illegal status in " __FUNCTION__
);
182 if (nss_next_action (*ni
, status
) == NSS_ACTION_RETURN
)
186 if ((*ni
)->next
== NULL
)
193 *fctp
= __nss_lookup_function (*ni
, fct_name
);
196 && nss_next_action (*ni
, NSS_STATUS_UNAVAIL
) == NSS_ACTION_CONTINUE
197 && (*ni
)->next
!= NULL
);
199 return *fctp
!= NULL
? 0 : -1;
204 __nss_configure_lookup (const char *dbname
, const char *service_line
)
206 service_user
*new_db
;
209 for (cnt
= 0; cnt
< sizeof databases
; ++cnt
)
211 int cmp
= strcmp (dbname
, databases
[cnt
].name
);
216 __set_errno (EINVAL
);
221 if (cnt
== sizeof databases
)
223 __set_errno (EINVAL
);
227 /* Test whether it is really used. */
228 if (databases
[cnt
].dbp
== NULL
)
229 /* Nothing to do, but we could do. */
232 /* Try to generate new data. */
233 new_db
= nss_parse_service_list (service_line
);
236 /* Illegal service specification. */
237 __set_errno (EINVAL
);
241 /* Prevent multiple threads to change the service table. */
242 __libc_lock_lock (lock
);
244 /* Install new rules. */
245 *databases
[cnt
].dbp
= new_db
;
247 __libc_lock_unlock (lock
);
253 /* Comparison function for searching NI->known tree. */
255 known_compare (const void *p1
, const void *p2
)
257 return p1
== p2
? 0 : strcmp (*(const char *const *) p1
,
258 *(const char *const *) p2
);
263 __nss_lookup_function (service_user
*ni
, const char *fct_name
)
265 void **found
, *result
;
267 /* We now modify global data. Protect it. */
268 __libc_lock_lock (lock
);
270 /* Search the tree of functions previously requested. Data in the
271 tree are `known_function' structures, whose first member is a
272 `const char *', the lookup key. The search returns a pointer to
273 the tree node structure; the first member of the is a pointer to
274 our structure (i.e. what will be a `known_function'); since the
275 first member of that is the lookup key string, &FCT_NAME is close
276 enough to a pointer to our structure to use as a lookup key that
277 will be passed to `known_compare' (above). */
279 found
= __tsearch (&fct_name
, (void **) &ni
->known
, &known_compare
);
280 if (*found
!= &fct_name
)
281 /* The search found an existing structure in the tree. */
282 result
= ((known_function
*) *found
)->fct_ptr
;
285 /* This name was not known before. Now we have a node in the tree
286 (in the proper sorted position for FCT_NAME) that points to
287 &FCT_NAME instead of any real `known_function' structure.
288 Allocate a new structure and fill it in. */
290 known_function
*known
= malloc (sizeof *known
);
294 /* Oops. We can't instantiate this node properly.
295 Remove it from the tree. */
296 __tdelete (&fct_name
, (void **) &ni
->known
, &known_compare
);
301 /* Point the tree node at this new structure. */
303 known
->fct_name
= fct_name
;
305 if (ni
->library
== NULL
)
307 /* This service has not yet been used. Fetch the service
308 library for it, creating a new one if need be. If there
309 is no service table from the file, this static variable
310 holds the head of the service_library list made from the
311 default configuration. */
312 static name_database default_table
;
313 ni
->library
= nss_new_service (service_table
?: &default_table
,
315 if (ni
->library
== NULL
)
317 /* This only happens when out of memory. */
319 goto remove_from_tree
;
323 #if !defined DO_STATIC_NSS || defined SHARED
324 if (ni
->library
->lib_handle
== NULL
)
326 /* Load the shared library. */
327 size_t shlen
= (7 + strlen (ni
->library
->name
) + 3
328 + strlen (__nss_shlib_revision
) + 1);
329 int saved_errno
= errno
;
330 char shlib_name
[shlen
];
332 /* Construct shared object name. */
333 __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name
,
337 __nss_shlib_revision
);
339 ni
->library
->lib_handle
= __libc_dlopen (shlib_name
);
340 if (ni
->library
->lib_handle
== NULL
)
342 /* Failed to load the library. */
343 ni
->library
->lib_handle
= (void *) -1l;
344 __set_errno (saved_errno
);
348 if (ni
->library
->lib_handle
== (void *) -1l)
349 /* Library not found => function not found. */
353 /* Get the desired function. */
354 size_t namlen
= (5 + strlen (ni
->library
->name
) + 1
355 + strlen (fct_name
) + 1);
358 /* Construct the function name. */
359 __stpcpy (__stpcpy (__stpcpy (__stpcpy (name
, "_nss_"),
364 /* Look up the symbol. */
365 result
= __libc_dlsym (ni
->library
->lib_handle
, name
);
368 /* We can't get function address dynamically in static linking. */
370 # define DEFINE_ENT(h,nm) \
371 { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \
372 { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \
373 { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
374 # define DEFINE_GET(h,nm) \
375 { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
376 # define DEFINE_GETBY(h,nm,ky) \
377 { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
378 static struct fct_tbl
{ const char *fname
; void *fp
; } *tp
, tbl
[] =
380 # include "function.def"
383 size_t namlen
= (5 + strlen (ni
->library
->name
) + 1
384 + strlen (fct_name
) + 1);
387 /* Construct the function name. */
388 __stpcpy (__stpcpy (__stpcpy (name
, ni
->library
->name
),
393 for (tp
= &tbl
[0]; tp
->fname
; tp
++)
394 if (strcmp (tp
->fname
, name
) == 0)
402 /* Remember function pointer for later calls. Even if null, we
403 record it so a second try needn't search the library again. */
404 known
->fct_ptr
= result
;
408 /* Remove the lock. */
409 __libc_lock_unlock (lock
);
415 static name_database
*
417 nss_parse_file (const char *fname
)
420 name_database
*result
;
421 name_database_entry
*last
;
425 /* Open the configuration file. */
426 fp
= fopen (fname
, "r");
430 result
= (name_database
*) malloc (sizeof (name_database
));
434 result
->entry
= NULL
;
435 result
->library
= NULL
;
441 name_database_entry
*this;
444 n
= __getline (&line
, &len
, fp
);
447 if (line
[n
- 1] == '\n')
450 /* Because the file format does not know any form of quoting we
451 can search forward for the next '#' character and if found
452 make it terminating the line. */
453 *__strchrnul (line
, '#') = '\0';
455 /* If the line is blank it is ignored. */
459 /* Each line completely specifies the actions for a database. */
460 this = nss_getline (line
);
466 result
->entry
= this;
471 while (!feof_unlocked (fp
));
473 /* Free the buffer. */
475 /* Close configuration file. */
482 /* Read the source names:
483 `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
485 static service_user
*
487 nss_parse_service_list (const char *line
)
489 service_user
*result
= NULL
, **nextp
= &result
;
493 service_user
*new_service
;
496 while (isspace (line
[0]))
499 /* No source specified. */
502 /* Read <source> identifier. */
504 while (line
[0] != '\0' && !isspace (line
[0]) && line
[0] != '[')
510 new_service
= (service_user
*) malloc (sizeof (service_user
)
511 + (line
- name
+ 1));
512 if (new_service
== NULL
)
515 *((char *) __mempcpy (new_service
->name
, name
, line
- name
)) = '\0';
517 /* Set default actions. */
518 new_service
->actions
[2 + NSS_STATUS_TRYAGAIN
] = NSS_ACTION_CONTINUE
;
519 new_service
->actions
[2 + NSS_STATUS_UNAVAIL
] = NSS_ACTION_CONTINUE
;
520 new_service
->actions
[2 + NSS_STATUS_NOTFOUND
] = NSS_ACTION_CONTINUE
;
521 new_service
->actions
[2 + NSS_STATUS_SUCCESS
] = NSS_ACTION_RETURN
;
522 new_service
->actions
[2 + NSS_STATUS_RETURN
] = NSS_ACTION_RETURN
;
523 new_service
->library
= NULL
;
524 new_service
->known
= NULL
;
525 new_service
->next
= NULL
;
527 while (isspace (line
[0]))
532 /* Read criterions. */
535 while (line
[0] != '\0' && isspace (line
[0]));
540 enum nss_status status
;
541 lookup_actions action
;
543 /* Grok ! before name to mean all statii but that one. */
544 not = line
[0] == '!';
548 /* Read status name. */
550 while (line
[0] != '\0' && !isspace (line
[0]) && line
[0] != '='
554 /* Compare with known statii. */
555 if (line
- name
== 7)
557 if (__strncasecmp (name
, "SUCCESS", 7) == 0)
558 status
= NSS_STATUS_SUCCESS
;
559 else if (__strncasecmp (name
, "UNAVAIL", 7) == 0)
560 status
= NSS_STATUS_UNAVAIL
;
564 else if (line
- name
== 8)
566 if (__strncasecmp (name
, "NOTFOUND", 8) == 0)
567 status
= NSS_STATUS_NOTFOUND
;
568 else if (__strncasecmp (name
, "TRYAGAIN", 8) == 0)
569 status
= NSS_STATUS_TRYAGAIN
;
576 while (isspace (line
[0]))
582 while (isspace (line
[0]));
585 while (line
[0] != '\0' && !isspace (line
[0]) && line
[0] != '='
589 if (line
- name
== 6 && __strncasecmp (name
, "RETURN", 6) == 0)
590 action
= NSS_ACTION_RETURN
;
591 else if (line
- name
== 8
592 && __strncasecmp (name
, "CONTINUE", 8) == 0)
593 action
= NSS_ACTION_CONTINUE
;
599 /* Save the current action setting for this status,
600 set them all to the given action, and reset this one. */
601 const lookup_actions save
= new_service
->actions
[2 + status
];
602 new_service
->actions
[2 + NSS_STATUS_TRYAGAIN
] = action
;
603 new_service
->actions
[2 + NSS_STATUS_UNAVAIL
] = action
;
604 new_service
->actions
[2 + NSS_STATUS_NOTFOUND
] = action
;
605 new_service
->actions
[2 + NSS_STATUS_SUCCESS
] = action
;
606 new_service
->actions
[2 + status
] = save
;
609 new_service
->actions
[2 + status
] = action
;
611 /* Skip white spaces. */
612 while (isspace (line
[0]))
615 while (line
[0] != ']');
621 *nextp
= new_service
;
622 nextp
= &new_service
->next
;
626 static name_database_entry
*
628 nss_getline (char *line
)
631 name_database_entry
*result
;
634 /* Ignore leading white spaces. ATTENTION: this is different from
635 what is implemented in Solaris. The Solaris man page says a line
636 beginning with a white space character is ignored. We regard
637 this as just another misfeature in Solaris. */
638 while (isspace (line
[0]))
641 /* Recognize `<database> ":"'. */
643 while (line
[0] != '\0' && !isspace (line
[0]) && line
[0] != ':')
645 if (line
[0] == '\0' || name
== line
)
650 len
= strlen (name
) + 1;
652 result
= (name_database_entry
*) malloc (sizeof (name_database_entry
) + len
);
656 /* Save the database name. */
657 memcpy (result
->name
, name
, len
);
659 /* Parse the list of services. */
660 result
->service
= nss_parse_service_list (line
);
667 static service_library
*
669 nss_new_service (name_database
*database
, const char *name
)
671 service_library
**currentp
= &database
->library
;
673 while (*currentp
!= NULL
)
675 if (strcmp ((*currentp
)->name
, name
) == 0)
677 currentp
= &(*currentp
)->next
;
680 /* We have to add the new service. */
681 *currentp
= (service_library
*) malloc (sizeof (service_library
));
682 if (*currentp
== NULL
)
685 (*currentp
)->name
= name
;
686 (*currentp
)->lib_handle
= NULL
;
687 (*currentp
)->next
= NULL
;
693 /* Free all resources if necessary. */
694 static void __attribute__ ((unused
))
697 name_database
*top
= service_table
;
698 name_database_entry
*entry
;
699 service_library
*library
;
702 /* Maybe we have not read the nsswitch.conf file. */
705 /* Don't disturb ongoing other threads (if there are any). */
706 service_table
= NULL
;
709 while (entry
!= NULL
)
711 name_database_entry
*olde
= entry
;
712 service_user
*service
= entry
->service
;
714 while (service
!= NULL
)
716 service_user
*olds
= service
;
718 if (service
->known
!= NULL
)
719 __tdestroy (service
->known
, free
);
721 service
= service
->next
;
729 library
= top
->library
;
730 while (library
!= NULL
)
732 service_library
*oldl
= library
;
734 __libc_dlclose (library
->lib_handle
);
736 library
= library
->next
;
743 text_set_element (__libc_subfreeres
, free_mem
);