nsswitch.c 24 KB

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