]>
Commit | Line | Data |
---|---|---|
5f0e6fc7 RM |
1 | /* Copyright (C) 1996 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 Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | 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 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If | |
17 | not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #include <ctype.h> | |
21 | #include <dlfcn.h> | |
a8874ead | 22 | #include <errno.h> |
5f0e6fc7 RM |
23 | #include <netdb.h> |
24 | #include <libc-lock.h> | |
25 | #include <search.h> | |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | ||
30 | #include "nsswitch.h" | |
31 | #include "../elf/link.h" /* We need some help from ld.so. */ | |
32 | ||
33 | /* Prototypes for the local functions. */ | |
5f0e6fc7 | 34 | static void *nss_lookup_function (service_user *ni, const char *fct_name); |
5f0e6fc7 RM |
35 | static name_database *nss_parse_file (const char *fname); |
36 | static name_database_entry *nss_getline (char *line); | |
bba7bb78 | 37 | static service_user *nss_parse_service_list (const char *line); |
5f0e6fc7 RM |
38 | static service_library *nss_new_service (name_database *database, |
39 | const char *name); | |
40 | ||
41 | ||
a8874ead UD |
42 | /* Declare external database variables. */ |
43 | #define DEFINE_DATABASE(name) \ | |
44 | extern service_user *__nss_##name##_database; \ | |
45 | weak_extern (__nss_##name##_database) | |
46 | #include "databases.def" | |
47 | #undef DEFINE_DATABASE | |
48 | ||
49 | /* Structure to map database name to variable. */ | |
50 | static struct | |
51 | { | |
52 | const char *name; | |
53 | service_user **dbp; | |
54 | } databases[] = | |
55 | { | |
56 | #define DEFINE_DATABASE(name) \ | |
57 | { #name, &__nss_##name##_database }, | |
58 | #include "databases.def" | |
59 | #undef DEFINE_DATABASE | |
60 | }; | |
61 | ||
62 | ||
1e16111c | 63 | __libc_lock_define_initialized (static, lock) |
5f0e6fc7 RM |
64 | |
65 | ||
5f0e6fc7 RM |
66 | /* Nonzero if the sevices are already initialized. */ |
67 | static int nss_initialized; | |
68 | ||
69 | ||
70 | /* The root of the whole data base. */ | |
71 | static name_database *service_table; | |
72 | ||
73 | ||
5f0e6fc7 RM |
74 | /* -1 == database not found |
75 | 0 == database entry pointer stored */ | |
76 | int | |
bba7bb78 RM |
77 | __nss_database_lookup (const char *database, const char *defconfig, |
78 | service_user **ni) | |
5f0e6fc7 | 79 | { |
a8874ead UD |
80 | /* Prevent multiple threads to change the service table. */ |
81 | __libc_lock_lock (lock); | |
bba7bb78 | 82 | |
a8874ead UD |
83 | /* Reconsider database variable in case some other thread called |
84 | `__nss_configure_lookup' while we waited for the lock. */ | |
85 | if (*ni != NULL) | |
15a83d04 UD |
86 | { |
87 | __libc_lock_unlock (lock); | |
88 | return 0; | |
89 | } | |
a8874ead UD |
90 | |
91 | if (nss_initialized == 0 && service_table == NULL) | |
92 | /* Read config file. */ | |
93 | service_table = nss_parse_file (_PATH_NSSWITCH_CONF); | |
5f0e6fc7 RM |
94 | |
95 | /* Test whether configuration data is available. */ | |
a8874ead | 96 | if (service_table != NULL) |
5f0e6fc7 | 97 | { |
a8874ead UD |
98 | /* Return first `service_user' entry for DATABASE. */ |
99 | name_database_entry *entry; | |
c66273aa RM |
100 | |
101 | /* XXX Could use some faster mechanism here. But each database is | |
102 | only requested once and so this might not be critical. */ | |
103 | for (entry = service_table->entry; entry != NULL; entry = entry->next) | |
104 | if (strcmp (database, entry->name) == 0) | |
15a83d04 | 105 | *ni = entry->service; |
5f0e6fc7 RM |
106 | } |
107 | ||
c66273aa | 108 | /* No configuration data is available, either because nsswitch.conf |
a8874ead UD |
109 | doesn't exist or because it doesn't has a line for this database. |
110 | ||
111 | DEFCONFIG specifies the default service list for this database, | |
bba7bb78 | 112 | or null to use the most common default. */ |
15a83d04 UD |
113 | if (*ni == NULL) |
114 | *ni = nss_parse_service_list (defconfig | |
115 | ?: "compat [NOTFOUND=return] files"); | |
a8874ead UD |
116 | |
117 | __libc_lock_unlock (lock); | |
bba7bb78 | 118 | |
5f0e6fc7 RM |
119 | return 0; |
120 | } | |
121 | ||
122 | ||
123 | /* -1 == not found | |
124 | 0 == adjusted for next function */ | |
125 | int | |
126 | __nss_lookup (service_user **ni, const char *fct_name, void **fctp) | |
127 | { | |
128 | *fctp = nss_lookup_function (*ni, fct_name); | |
129 | ||
130 | while (*fctp == NULL | |
131 | && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE | |
132 | && (*ni)->next != NULL) | |
133 | { | |
134 | *ni = (*ni)->next; | |
135 | ||
136 | *fctp = nss_lookup_function (*ni, fct_name); | |
137 | } | |
138 | ||
139 | return *fctp != NULL ? 0 : -1; | |
140 | } | |
141 | ||
142 | ||
143 | /* -1 == not found | |
144 | 0 == adjusted for next function | |
145 | 1 == finished */ | |
146 | int | |
147 | __nss_next (service_user **ni, const char *fct_name, void **fctp, int status, | |
148 | int all_values) | |
149 | { | |
150 | if (all_values) | |
151 | { | |
152 | if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN | |
153 | && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN | |
154 | && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN | |
155 | && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN) | |
156 | return 1; | |
157 | } | |
158 | else | |
159 | { | |
160 | /* This is really only for debugging. */ | |
161 | if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_SUCCESS) | |
162 | __libc_fatal ("illegal status in " __FUNCTION__); | |
163 | ||
164 | if (nss_next_action (*ni, status) == NSS_ACTION_RETURN) | |
165 | return 1; | |
166 | } | |
167 | ||
168 | if ((*ni)->next == NULL) | |
169 | return -1; | |
170 | ||
171 | do | |
172 | { | |
173 | *ni = (*ni)->next; | |
174 | ||
175 | *fctp = nss_lookup_function (*ni, fct_name); | |
176 | } | |
177 | while (*fctp == NULL | |
178 | && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE | |
179 | && (*ni)->next != NULL); | |
180 | ||
181 | return *fctp != NULL ? 0 : -1; | |
182 | } | |
183 | ||
184 | ||
a8874ead UD |
185 | int |
186 | __nss_configure_lookup (const char *dbname, const char *service_line) | |
187 | { | |
188 | service_user *new_db; | |
189 | size_t cnt; | |
190 | ||
191 | for (cnt = 0; cnt < sizeof databases; ++cnt) | |
192 | if (strcmp (dbname, databases[cnt].name) == 0) | |
193 | break; | |
194 | ||
195 | if (cnt == sizeof databases) | |
196 | { | |
197 | errno = EINVAL; | |
198 | return -1; | |
199 | } | |
200 | ||
201 | /* Test whether it is really used. */ | |
202 | if (databases[cnt].dbp == NULL) | |
203 | /* Nothing to do, but we could do. */ | |
204 | return 0; | |
205 | ||
206 | /* Try to generate new data. */ | |
207 | new_db = nss_parse_service_list (service_line); | |
208 | if (new_db == NULL) | |
209 | { | |
210 | /* Illegal service specification. */ | |
211 | errno = EINVAL; | |
212 | return -1; | |
213 | } | |
214 | ||
215 | /* Prevent multiple threads to change the service table. */ | |
216 | __libc_lock_lock (lock); | |
217 | ||
218 | /* Install new rules. */ | |
219 | *databases[cnt].dbp = new_db; | |
220 | ||
221 | __libc_lock_unlock (lock); | |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
226 | ||
5f0e6fc7 RM |
227 | static int |
228 | nss_dlerror_run (void (*operate) (void)) | |
229 | { | |
230 | const char *last_errstring = NULL; | |
231 | const char *last_object_name = NULL; | |
232 | ||
233 | (void) _dl_catch_error (&last_errstring, &last_object_name, operate); | |
234 | ||
235 | return last_errstring != NULL; | |
236 | } | |
237 | ||
238 | ||
2064087b RM |
239 | /* Comparison function for searching NI->known tree. */ |
240 | static int | |
241 | known_compare (const void *p1, const void *p2) | |
242 | { | |
243 | return p1 == p2 ? 0 : strcmp (*(const char *const *) p1, | |
244 | *(const char *const *) p2); | |
245 | } | |
246 | ||
247 | ||
5f0e6fc7 RM |
248 | static void * |
249 | nss_lookup_function (service_user *ni, const char *fct_name) | |
250 | { | |
dbe31b9a | 251 | void **found, *result; |
5f0e6fc7 | 252 | |
5f0e6fc7 RM |
253 | /* We now modify global data. Protect it. */ |
254 | __libc_lock_lock (lock); | |
255 | ||
dbe31b9a RM |
256 | /* Search the tree of functions previously requested. Data in the |
257 | tree are `known_function' structures, whose first member is a | |
258 | `const char *', the lookup key. The search returns a pointer to | |
259 | the tree node structure; the first member of the is a pointer to | |
260 | our structure (i.e. what will be a `known_function'); since the | |
261 | first member of that is the lookup key string, &FCT_NAME is close | |
262 | enough to a pointer to our structure to use as a lookup key that | |
263 | will be passed to `known_compare' (above). */ | |
264 | ||
265 | found = __tsearch (&fct_name, (void **) &ni->known, &known_compare); | |
266 | if (*found != &fct_name) | |
267 | /* The search found an existing structure in the tree. */ | |
268 | result = ((known_function *) *found)->fct_ptr; | |
269 | else | |
5f0e6fc7 | 270 | { |
dbe31b9a RM |
271 | /* This name was not known before. Now we have a node in the tree |
272 | (in the proper sorted position for FCT_NAME) that points to | |
273 | &FCT_NAME instead of any real `known_function' structure. | |
274 | Allocate a new structure and fill it in. */ | |
5f0e6fc7 | 275 | |
dbe31b9a RM |
276 | known_function *known = malloc (sizeof *known); |
277 | if (! known) | |
5f0e6fc7 | 278 | { |
dbe31b9a RM |
279 | remove_from_tree: |
280 | /* Oops. We can't instantiate this node properly. | |
281 | Remove it from the tree. */ | |
282 | __tdelete (&fct_name, (void **) &ni->known, &known_compare); | |
283 | result = NULL; | |
5f0e6fc7 | 284 | } |
dbe31b9a | 285 | else |
5f0e6fc7 | 286 | { |
dbe31b9a RM |
287 | /* Point the tree node at this new structure. */ |
288 | *found = known; | |
289 | known->fct_name = fct_name; | |
290 | ||
291 | if (ni->library == NULL) | |
292 | { | |
293 | /* This service has not yet been used. Fetch the service | |
294 | library for it, creating a new one if need be. If there | |
295 | is no service table from the file, this static variable | |
296 | holds the head of the service_library list made from the | |
297 | default configuration. */ | |
298 | static name_database default_table; | |
299 | ni->library = nss_new_service (service_table ?: &default_table, | |
300 | ni->name); | |
301 | if (ni->library == NULL) | |
302 | { | |
303 | /* This only happens when out of memory. */ | |
304 | free (known); | |
305 | goto remove_from_tree; | |
306 | } | |
307 | } | |
308 | ||
309 | if (ni->library->lib_handle == NULL) | |
310 | { | |
311 | /* Load the shared library. */ | |
312 | size_t shlen = (7 + strlen (ni->library->name) + 3 | |
313 | + sizeof (NSS_SHLIB_REVISION)); | |
314 | char shlib_name[shlen]; | |
315 | ||
316 | void do_open (void) | |
317 | { | |
318 | /* Open and relocate the shared object. */ | |
319 | ni->library->lib_handle = _dl_open (shlib_name, RTLD_LAZY); | |
320 | } | |
321 | ||
322 | /* Construct shared object name. */ | |
323 | __stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_"), | |
324 | ni->library->name), | |
325 | ".so" NSS_SHLIB_REVISION); | |
326 | ||
327 | if (nss_dlerror_run (do_open) != 0) | |
328 | /* Failed to load the library. */ | |
329 | ni->library->lib_handle = (void *) -1; | |
330 | } | |
331 | ||
332 | if (ni->library->lib_handle == (void *) -1) | |
333 | /* Library not found => function not found. */ | |
334 | result = NULL; | |
335 | else | |
336 | { | |
337 | /* Get the desired function. Again, GNU ld.so magic ahead. */ | |
338 | size_t namlen = (5 + strlen (ni->library->name) + 1 | |
339 | + strlen (fct_name) + 1); | |
340 | char name[namlen]; | |
341 | struct link_map *map = ni->library->lib_handle; | |
342 | ElfW(Addr) loadbase; | |
343 | const ElfW(Sym) *ref = NULL; | |
344 | void get_sym (void) | |
345 | { | |
346 | struct link_map *scope[2] = { map, NULL }; | |
347 | loadbase = _dl_lookup_symbol (name, &ref, | |
348 | scope, map->l_name, 0, 0); | |
349 | } | |
350 | ||
351 | /* Construct the function name. */ | |
352 | __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"), | |
353 | ni->library->name), | |
354 | "_"), | |
355 | fct_name); | |
356 | ||
357 | /* Look up the symbol. */ | |
358 | result = (nss_dlerror_run (get_sym) | |
359 | ? NULL : (void *) (loadbase + ref->st_value)); | |
360 | } | |
361 | ||
362 | /* Remember function pointer for later calls. Even if null, we | |
363 | record it so a second try needn't search the library again. */ | |
364 | known->fct_ptr = result; | |
5f0e6fc7 | 365 | } |
5f0e6fc7 RM |
366 | } |
367 | ||
5f0e6fc7 RM |
368 | /* Remove the lock. */ |
369 | __libc_lock_unlock (lock); | |
370 | ||
371 | return result; | |
372 | } | |
373 | ||
374 | ||
5f0e6fc7 RM |
375 | static name_database * |
376 | nss_parse_file (const char *fname) | |
377 | { | |
378 | FILE *fp; | |
379 | name_database *result; | |
380 | name_database_entry *last; | |
381 | char *line; | |
382 | size_t len; | |
383 | ||
384 | /* Open the configuration file. */ | |
385 | fp = fopen (fname, "r"); | |
386 | if (fp == NULL) | |
387 | return NULL; | |
388 | ||
389 | result = (name_database *) malloc (sizeof (name_database)); | |
390 | if (result == NULL) | |
391 | return NULL; | |
392 | ||
393 | result->entry = NULL; | |
394 | result->library = NULL; | |
395 | last = NULL; | |
396 | line = NULL; | |
397 | len = 0; | |
398 | do | |
399 | { | |
400 | name_database_entry *this; | |
401 | ssize_t n; | |
402 | char *cp; | |
403 | ||
bba7bb78 | 404 | n = __getline (&line, &len, fp); |
5f0e6fc7 RM |
405 | if (n < 0) |
406 | break; | |
407 | if (line[n - 1] == '\n') | |
408 | line[n - 1] = '\0'; | |
409 | ||
410 | /* Because the file format does not know any form of quoting we | |
411 | can search forward for the next '#' character and if found | |
412 | make it terminating the line. */ | |
413 | cp = strchr (line, '#'); | |
414 | if (cp != NULL) | |
415 | *cp = '\0'; | |
416 | ||
417 | /* If the line is blank it is ignored. */ | |
418 | if (line[0] == '\0') | |
419 | continue; | |
420 | ||
421 | /* Each line completely specifies the actions for a database. */ | |
422 | this = nss_getline (line); | |
423 | if (this != NULL) | |
424 | { | |
425 | if (last != NULL) | |
426 | last->next = this; | |
427 | else | |
428 | result->entry = this; | |
429 | ||
430 | last = this; | |
431 | } | |
432 | } | |
433 | while (!feof (fp)); | |
434 | ||
435 | /* Free the buffer. */ | |
436 | free (line); | |
437 | /* Close configuration file. */ | |
438 | fclose (fp); | |
439 | ||
5f0e6fc7 RM |
440 | return result; |
441 | } | |
442 | ||
443 | ||
a8874ead UD |
444 | /* Read the source names: |
445 | `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*' | |
446 | */ | |
bba7bb78 RM |
447 | static service_user * |
448 | nss_parse_service_list (const char *line) | |
5f0e6fc7 | 449 | { |
bba7bb78 | 450 | service_user *result = NULL, **nextp = &result; |
5f0e6fc7 | 451 | |
5f0e6fc7 RM |
452 | while (1) |
453 | { | |
454 | service_user *new_service; | |
3776d592 | 455 | const char *name; |
5f0e6fc7 RM |
456 | |
457 | while (isspace (line[0])) | |
458 | ++line; | |
459 | if (line[0] == '\0') | |
460 | /* No source specified. */ | |
461 | return result; | |
462 | ||
463 | /* Read <source> identifier. */ | |
464 | name = line; | |
465 | while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[') | |
466 | ++line; | |
467 | if (name == line) | |
468 | return result; | |
469 | ||
470 | ||
471 | new_service = (service_user *) malloc (sizeof (service_user)); | |
472 | if (new_service == NULL) | |
473 | return result; | |
5f0e6fc7 RM |
474 | else |
475 | { | |
476 | char *source = (char *) malloc (line - name + 1); | |
477 | if (source == NULL) | |
478 | { | |
479 | free (new_service); | |
480 | return result; | |
481 | } | |
482 | memcpy (source, name, line - name); | |
483 | source[line - name] = '\0'; | |
484 | ||
485 | new_service->name = source; | |
486 | } | |
487 | ||
488 | /* Set default actions. */ | |
489 | new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE; | |
490 | new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE; | |
491 | new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE; | |
492 | new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN; | |
493 | new_service->library = NULL; | |
494 | new_service->known = NULL; | |
495 | new_service->next = NULL; | |
496 | ||
497 | while (isspace (line[0])) | |
498 | ++line; | |
499 | ||
500 | if (line[0] == '[') | |
501 | { | |
5f0e6fc7 RM |
502 | /* Read criterions. */ |
503 | do | |
504 | ++line; | |
505 | while (line[0] != '\0' && isspace (line[0])); | |
506 | ||
507 | do | |
508 | { | |
bba7bb78 RM |
509 | int not; |
510 | enum nss_status status; | |
511 | lookup_actions action; | |
512 | ||
513 | /* Grok ! before name to mean all statii but that one. */ | |
514 | if (not = line[0] == '!') | |
515 | ++line; | |
516 | ||
5f0e6fc7 RM |
517 | /* Read status name. */ |
518 | name = line; | |
519 | while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' | |
520 | && line[0] != ']') | |
521 | ++line; | |
522 | ||
523 | /* Compare with known statii. */ | |
524 | if (line - name == 7) | |
525 | { | |
bba7bb78 | 526 | if (__strncasecmp (name, "SUCCESS", 7) == 0) |
5f0e6fc7 | 527 | status = NSS_STATUS_SUCCESS; |
bba7bb78 | 528 | else if (__strncasecmp (name, "UNAVAIL", 7) == 0) |
5f0e6fc7 RM |
529 | status = NSS_STATUS_UNAVAIL; |
530 | else | |
531 | return result; | |
532 | } | |
533 | else if (line - name == 8) | |
534 | { | |
bba7bb78 | 535 | if (__strncasecmp (name, "NOTFOUND", 8) == 0) |
5f0e6fc7 | 536 | status = NSS_STATUS_NOTFOUND; |
bba7bb78 | 537 | else if (__strncasecmp (name, "TRYAGAIN", 8) == 0) |
5f0e6fc7 RM |
538 | status = NSS_STATUS_TRYAGAIN; |
539 | else | |
540 | return result; | |
541 | } | |
542 | else | |
543 | return result; | |
544 | ||
545 | while (isspace (line[0])) | |
546 | ++line; | |
547 | if (line[0] != '=') | |
548 | return result; | |
549 | do | |
550 | ++line; | |
551 | while (isspace (line[0])); | |
552 | ||
553 | name = line; | |
554 | while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' | |
555 | && line[0] != ']') | |
556 | ++line; | |
557 | ||
bba7bb78 RM |
558 | if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0) |
559 | action = NSS_ACTION_RETURN; | |
5f0e6fc7 | 560 | else if (line - name == 8 |
bba7bb78 RM |
561 | && __strncasecmp (name, "CONTINUE", 8) == 0) |
562 | action = NSS_ACTION_CONTINUE; | |
5f0e6fc7 RM |
563 | else |
564 | return result; | |
565 | ||
bba7bb78 RM |
566 | if (not) |
567 | { | |
568 | /* Save the current action setting for this status, | |
569 | set them all to the given action, and reset this one. */ | |
570 | const lookup_actions save = new_service->actions[2 + status]; | |
571 | new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action; | |
572 | new_service->actions[2 + NSS_STATUS_UNAVAIL] = action; | |
573 | new_service->actions[2 + NSS_STATUS_NOTFOUND] = action; | |
574 | new_service->actions[2 + NSS_STATUS_SUCCESS] = action; | |
575 | new_service->actions[2 + status] = save; | |
576 | } | |
577 | else | |
578 | new_service->actions[2 + status] = action; | |
579 | ||
580 | /* Skip white spaces. */ | |
5f0e6fc7 RM |
581 | while (isspace (line[0])) |
582 | ++line; | |
583 | } | |
584 | while (line[0] != ']'); | |
585 | ||
586 | /* Skip the ']'. */ | |
587 | ++line; | |
588 | } | |
589 | ||
bba7bb78 RM |
590 | *nextp = new_service; |
591 | nextp = &new_service->next; | |
5f0e6fc7 | 592 | } |
bba7bb78 RM |
593 | } |
594 | ||
595 | static name_database_entry * | |
596 | nss_getline (char *line) | |
597 | { | |
598 | const char *name; | |
599 | name_database_entry *result; | |
600 | ||
601 | /* Ignore leading white spaces. ATTENTION: this is different from | |
602 | what is implemented in Solaris. The Solaris man page says a line | |
603 | beginning with a white space character is ignored. We regard | |
604 | this as just another misfeature in Solaris. */ | |
605 | while (isspace (line[0])) | |
606 | ++line; | |
607 | ||
608 | /* Recognize `<database> ":"'. */ | |
609 | name = line; | |
610 | while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':') | |
611 | ++line; | |
612 | if (line[0] == '\0' || name == line) | |
613 | /* Syntax error. */ | |
614 | return NULL; | |
615 | *line++ = '\0'; | |
616 | ||
617 | result = (name_database_entry *) malloc (sizeof (name_database_entry)); | |
618 | if (result == NULL) | |
619 | return NULL; | |
620 | ||
621 | /* Save the database name. */ | |
622 | { | |
623 | const size_t len = strlen (name) + 1; | |
624 | char *new = malloc (len); | |
625 | if (new == NULL) | |
626 | { | |
627 | free (result); | |
628 | return NULL; | |
629 | } | |
630 | result->name = memcpy (new, name, len); | |
631 | } | |
632 | ||
633 | /* Parse the list of services. */ | |
634 | result->service = nss_parse_service_list (line); | |
635 | ||
636 | result->next = NULL; | |
637 | return result; | |
5f0e6fc7 RM |
638 | } |
639 | ||
640 | ||
641 | static service_library * | |
642 | nss_new_service (name_database *database, const char *name) | |
643 | { | |
644 | service_library **currentp = &database->library; | |
645 | ||
646 | while (*currentp != NULL) | |
647 | { | |
648 | if (strcmp ((*currentp)->name, name) == 0) | |
649 | return *currentp; | |
650 | currentp = &(*currentp)->next; | |
651 | } | |
652 | ||
653 | /* We have to add the new service. */ | |
654 | *currentp = (service_library *) malloc (sizeof (service_library)); | |
655 | if (*currentp == NULL) | |
656 | return NULL; | |
657 | ||
658 | (*currentp)->name = name; | |
659 | (*currentp)->lib_handle = NULL; | |
660 | (*currentp)->next = NULL; | |
661 | ||
662 | return *currentp; | |
663 | } |