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