1 /* Global list of NSS service modules.
2 Copyright (c) 2020-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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, see
17 <https://www.gnu.org/licenses/>. */
20 #include <nscd/nscd.h>
21 #include <nscd/nscd_proto.h>
23 #include <array_length.h>
27 #include <gnu/lib-names.h>
28 #include <libc-lock.h>
30 #include <nss_files.h>
37 /* Suffix after .so of NSS service modules. This is a bit of magic,
38 but we assume LIBNSS_FILES_SO looks like "libnss_files.so.2" and we
39 want a pointer to the ".2" part. We have no API to extract this
40 except through the auto-generated lib-names.h and some static
41 pointer manipulation. The "-1" accounts for the trailing NUL
42 included in the sizeof. */
43 static const char *const __nss_shlib_revision
44 = LIBNSS_FILES_SO
+ sizeof("libnss_files.so") - 1;
46 /* A single-linked list used to implement a mapping from service names
47 to NSS modules. (Most systems only use five or so modules, so a
48 list is sufficient here.) Elements of this list are never freed
49 during normal operation. */
50 static struct nss_module
*nss_module_list
;
52 /* Covers the list and also loading of individual NSS service
54 __libc_lock_define (static, nss_module_list_lock
);
56 #if defined USE_NSCD && (!defined DO_STATIC_NSS || defined SHARED)
57 /* Nonzero if this is the nscd process. */
59 /* The callback passed to the init functions when nscd is used. */
60 static void (*nscd_init_cb
) (size_t, struct traced_file
*);
63 /* Allocate the service NAME with length NAME_LENGTH. If the service
64 is already allocated in the nss_module_list cache then we return a
65 pointer to the struct nss_module, otherwise we try to allocate a
66 new struct nss_module entry and add it to the global
67 nss_modules_list cache. If we fail to allocate the entry we return
68 NULL. Failure to allocate the entry is always transient. */
70 __nss_module_allocate (const char *name
, size_t name_length
)
72 __libc_lock_lock (nss_module_list_lock
);
74 struct nss_module
*result
= NULL
;
75 for (struct nss_module
*p
= nss_module_list
; p
!= NULL
; p
= p
->next
)
76 if (strncmp (p
->name
, name
, name_length
) == 0
77 && p
->name
[name_length
] == '\0')
79 /* Return the previously existing object. */
86 /* Allocate a new list entry if the name was not found in the
88 result
= malloc (sizeof (*result
) + name_length
+ 1);
91 result
->state
= nss_module_uninitialized
;
92 memcpy (result
->name
, name
, name_length
);
93 result
->name
[name_length
] = '\0';
94 result
->handle
= NULL
;
95 result
->next
= nss_module_list
;
96 nss_module_list
= result
;
100 __libc_lock_unlock (nss_module_list_lock
);
104 /* Long enough to store the name of any function in the
105 nss_function_name_array list below, as getprotobynumber_r is the
106 longest entry in that list. */
107 typedef char function_name
[sizeof("getprotobynumber_r")];
109 static const function_name nss_function_name_array
[] =
111 #undef DEFINE_NSS_FUNCTION
112 #define DEFINE_NSS_FUNCTION(x) #x,
113 #include "function.def"
116 /* Loads a built-in module, binding the symbols using the supplied
117 callback function. Always returns true. */
119 module_load_builtin (struct nss_module
*module
,
120 void (*bind
) (nss_module_functions_untyped
))
122 /* Initialize the function pointers, following the double-checked
124 __libc_lock_lock (nss_module_list_lock
);
125 switch ((enum nss_module_state
) atomic_load_acquire (&module
->state
))
127 case nss_module_uninitialized
:
128 case nss_module_failed
:
129 bind (module
->functions
.untyped
);
132 for (int i
= 0; i
< nss_module_functions_count
; ++i
)
133 PTR_MANGLE (module
->functions
.untyped
[i
]);
136 module
->handle
= NULL
;
137 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
138 atomic_store_release (&module
->state
, nss_module_loaded
);
140 case nss_module_loaded
:
141 /* Nothing to clean up. */
144 __libc_lock_unlock (nss_module_list_lock
);
148 /* Loads the built-in nss_files module. */
150 module_load_nss_files (struct nss_module
*module
)
155 void (*cb
) (size_t, struct traced_file
*) = nscd_init_cb
;
159 _nss_files_init (cb
);
162 return module_load_builtin (module
, __nss_files_functions
);
165 /* Loads the built-in nss_dns module. */
167 module_load_nss_dns (struct nss_module
*module
)
169 return module_load_builtin (module
, __nss_dns_functions
);
172 /* Internal implementation of __nss_module_load. */
174 module_load (struct nss_module
*module
)
176 if (strcmp (module
->name
, "files") == 0)
177 return module_load_nss_files (module
);
178 if (strcmp (module
->name
, "dns") == 0)
179 return module_load_nss_dns (module
);
184 if (__asprintf (&shlib_name
, "libnss_%s.so%s",
185 module
->name
, __nss_shlib_revision
) < 0)
186 /* This is definitely a temporary failure. Do not update
187 module->state. This will trigger another attempt at the next
191 handle
= __libc_dlopen (shlib_name
);
195 /* Failing to load the module can be caused by several different
196 scenarios. One such scenario is that the module has been removed
197 from the disk. In which case the in-memory version is all that
198 we have, and if the module->state indidates it is loaded then we
202 /* dlopen failure. We do not know if this a temporary or
203 permanent error. See bug 22041. Update the state using the
204 double-checked locking idiom. */
206 __libc_lock_lock (nss_module_list_lock
);
207 bool result
= result
;
208 switch ((enum nss_module_state
) atomic_load_acquire (&module
->state
))
210 case nss_module_uninitialized
:
211 atomic_store_release (&module
->state
, nss_module_failed
);
214 case nss_module_loaded
:
217 case nss_module_failed
:
221 __libc_lock_unlock (nss_module_list_lock
);
225 nss_module_functions_untyped pointers
;
227 /* Look up and store locally all the function pointers we may need
228 later. Doing this now means the data will not change in the
230 for (size_t idx
= 0; idx
< array_length (nss_function_name_array
); ++idx
)
233 if (__asprintf (&function_name
, "_nss_%s_%s",
234 module
->name
, nss_function_name_array
[idx
]) < 0)
236 /* Definitely a temporary error. */
237 __libc_dlclose (handle
);
240 pointers
[idx
] = __libc_dlsym (handle
, function_name
);
241 free (function_name
);
243 PTR_MANGLE (pointers
[idx
]);
250 /* Call the init function when nscd is used. */
251 size_t initlen
= (5 + strlen (module
->name
)
252 + strlen ("_init") + 1);
253 char init_name
[initlen
];
255 /* Construct the init function name. */
256 __stpcpy (__stpcpy (__stpcpy (init_name
,
261 /* Find the optional init function. */
262 void (*ifct
) (void (*) (size_t, struct traced_file
*))
263 = __libc_dlsym (handle
, init_name
);
266 void (*cb
) (size_t, struct traced_file
*) = nscd_init_cb
;
275 /* Install the function pointers, following the double-checked
276 locking idiom. Delay this after all processing, in case loading
277 the module triggers unwinding. */
278 __libc_lock_lock (nss_module_list_lock
);
279 switch ((enum nss_module_state
) atomic_load_acquire (&module
->state
))
281 case nss_module_uninitialized
:
282 case nss_module_failed
:
283 memcpy (module
->functions
.untyped
, pointers
,
284 sizeof (module
->functions
.untyped
));
285 module
->handle
= handle
;
286 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
287 atomic_store_release (&module
->state
, nss_module_loaded
);
289 case nss_module_loaded
:
290 /* If the module was already loaded, close our own handle. This
291 does not actually unload the modules, only the reference
292 counter is decremented for the loaded module. */
293 __libc_dlclose (handle
);
296 __libc_lock_unlock (nss_module_list_lock
);
300 /* Force the module identified by MODULE to be loaded. We return
301 false if the module could not be loaded, true otherwise. Loading
302 the module requires looking up all the possible interface APIs and
303 caching the results. */
305 __nss_module_load (struct nss_module
*module
)
307 switch ((enum nss_module_state
) atomic_load_acquire (&module
->state
))
309 case nss_module_uninitialized
:
310 return module_load (module
);
311 case nss_module_loaded
:
312 /* Loading has already succeeded. */
314 case nss_module_failed
:
315 /* Loading previously failed. */
318 __builtin_unreachable ();
322 name_search (const void *left
, const void *right
)
324 return strcmp (left
, right
);
327 /* Load module MODULE (if it isn't already) and return a pointer to
328 the module's implementation of NAME, otherwise return NULL on
331 __nss_module_get_function (struct nss_module
*module
, const char *name
)
333 /* A successful dlopen might clobber errno. */
334 int saved_errno
= errno
;
336 if (!__nss_module_load (module
))
338 /* Reporting module load failure is currently inaccurate. See
339 bug 22041. Not changing errno is the conservative choice. */
340 __set_errno (saved_errno
);
344 __set_errno (saved_errno
);
346 function_name
*name_entry
= bsearch (name
, nss_function_name_array
,
347 array_length (nss_function_name_array
),
348 sizeof (function_name
), name_search
);
349 assert (name_entry
!= NULL
);
350 size_t idx
= name_entry
- nss_function_name_array
;
351 void *fptr
= module
->functions
.untyped
[idx
];
358 #if defined SHARED && defined USE_NSCD
359 /* Load all libraries for the service. */
361 nss_load_all_libraries (enum nss_database service
)
363 nss_action_list ni
= NULL
;
365 if (__nss_database_get (service
, &ni
))
366 while (ni
->module
!= NULL
)
368 __nss_module_load (ni
->module
);
373 define_traced_file (pwd
, _PATH_NSSWITCH_CONF
);
374 define_traced_file (grp
, _PATH_NSSWITCH_CONF
);
375 define_traced_file (hst
, _PATH_NSSWITCH_CONF
);
376 define_traced_file (serv
, _PATH_NSSWITCH_CONF
);
377 define_traced_file (netgr
, _PATH_NSSWITCH_CONF
);
379 /* Called by nscd and nscd alone. */
381 __nss_disable_nscd (void (*cb
) (size_t, struct traced_file
*))
383 void (*cb1
) (size_t, struct traced_file
*);
391 /* Find all the relevant modules so that the init functions are called. */
392 nss_load_all_libraries (nss_database_passwd
);
393 nss_load_all_libraries (nss_database_group
);
394 nss_load_all_libraries (nss_database_hosts
);
395 nss_load_all_libraries (nss_database_services
);
397 /* Make sure NSCD purges its cache if nsswitch.conf changes. */
398 init_traced_file (&pwd_traced_file
.file
, _PATH_NSSWITCH_CONF
, 0);
399 cb1 (pwddb
, &pwd_traced_file
.file
);
400 init_traced_file (&grp_traced_file
.file
, _PATH_NSSWITCH_CONF
, 0);
401 cb1 (grpdb
, &grp_traced_file
.file
);
402 init_traced_file (&hst_traced_file
.file
, _PATH_NSSWITCH_CONF
, 0);
403 cb1 (hstdb
, &hst_traced_file
.file
);
404 init_traced_file (&serv_traced_file
.file
, _PATH_NSSWITCH_CONF
, 0);
405 cb1 (servdb
, &serv_traced_file
.file
);
406 init_traced_file (&netgr_traced_file
.file
, _PATH_NSSWITCH_CONF
, 0);
407 cb1 (netgrdb
, &netgr_traced_file
.file
);
409 /* Disable all uses of NSCD. */
410 __nss_not_use_nscd_passwd
= -1;
411 __nss_not_use_nscd_group
= -1;
412 __nss_not_use_nscd_hosts
= -1;
413 __nss_not_use_nscd_services
= -1;
414 __nss_not_use_nscd_netgroup
= -1;
418 /* Block attempts to dlopen any module we haven't already opened. */
420 __nss_module_disable_loading (void)
422 __libc_lock_lock (nss_module_list_lock
);
424 for (struct nss_module
*p
= nss_module_list
; p
!= NULL
; p
= p
->next
)
425 if (p
->state
== nss_module_uninitialized
)
426 p
->state
= nss_module_failed
;
428 __libc_lock_unlock (nss_module_list_lock
);
431 void __libc_freeres_fn_section
432 __nss_module_freeres (void)
434 struct nss_module
*current
= nss_module_list
;
435 while (current
!= NULL
)
437 /* Ignore built-in modules (which have a NULL handle). */
438 if (current
->state
== nss_module_loaded
439 && current
->handle
!= NULL
)
440 __libc_dlclose (current
->handle
);
442 struct nss_module
*next
= current
->next
;
446 nss_module_list
= NULL
;