]> sourceware.org Git - glibc.git/blame - nss/nss_module.c
nss: Reconcile conditional declaration and use of `is_nscd'
[glibc.git] / nss / nss_module.c
CommitLineData
171689da 1/* Global list of NSS service modules.
6d7e8eda 2 Copyright (c) 2020-2023 Free Software Foundation, Inc.
171689da
FW
3 This file is part of the GNU C Library.
4
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.
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 Lesser General Public License for more details.
14
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/>. */
18
f8847d83
DD
19#include <nsswitch.h>
20#include <nscd/nscd.h>
21#include <nscd/nscd_proto.h>
171689da
FW
22
23#include <array_length.h>
24#include <assert.h>
25#include <atomic.h>
26#include <dlfcn.h>
27#include <gnu/lib-names.h>
28#include <libc-lock.h>
ee5ed999
FW
29#include <nss_dns.h>
30#include <nss_files.h>
171689da
FW
31#include <stddef.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
88f4b692 35#include <pointer_guard.h>
171689da 36
171689da
FW
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. */
43static const char *const __nss_shlib_revision
44 = LIBNSS_FILES_SO + sizeof("libnss_files.so") - 1;
45
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. */
50static struct nss_module *nss_module_list;
51
52/* Covers the list and also loading of individual NSS service
53 modules. */
54__libc_lock_define (static, nss_module_list_lock);
55
bea1a4a7 56#if defined SHARED && defined USE_NSCD
171689da
FW
57/* Nonzero if this is the nscd process. */
58static bool is_nscd;
59/* The callback passed to the init functions when nscd is used. */
60static void (*nscd_init_cb) (size_t, struct traced_file *);
61#endif
62
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. */
69struct nss_module *
70__nss_module_allocate (const char *name, size_t name_length)
71{
72 __libc_lock_lock (nss_module_list_lock);
73
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')
78 {
79 /* Return the previously existing object. */
80 result = p;
81 break;
82 }
83
84 if (result == NULL)
85 {
86 /* Allocate a new list entry if the name was not found in the
87 list. */
88 result = malloc (sizeof (*result) + name_length + 1);
89 if (result != NULL)
90 {
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;
97 }
98 }
99
100 __libc_lock_unlock (nss_module_list_lock);
101 return result;
102}
103
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. */
107typedef char function_name[sizeof("getprotobynumber_r")];
108
109static const function_name nss_function_name_array[] =
110 {
111#undef DEFINE_NSS_FUNCTION
112#define DEFINE_NSS_FUNCTION(x) #x,
113#include "function.def"
114 };
115
ee5ed999
FW
116/* Loads a built-in module, binding the symbols using the supplied
117 callback function. Always returns true. */
f9c8b11e 118static bool
ee5ed999
FW
119module_load_builtin (struct nss_module *module,
120 void (*bind) (nss_module_functions_untyped))
f9c8b11e 121{
f9c8b11e
FW
122 /* Initialize the function pointers, following the double-checked
123 locking idiom. */
124 __libc_lock_lock (nss_module_list_lock);
125 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
126 {
127 case nss_module_uninitialized:
128 case nss_module_failed:
ee5ed999
FW
129 bind (module->functions.untyped);
130
ee5ed999
FW
131 for (int i = 0; i < nss_module_functions_count; ++i)
132 PTR_MANGLE (module->functions.untyped[i]);
ee5ed999 133
f9c8b11e
FW
134 module->handle = NULL;
135 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
136 atomic_store_release (&module->state, nss_module_loaded);
137 break;
138 case nss_module_loaded:
139 /* Nothing to clean up. */
140 break;
141 }
142 __libc_lock_unlock (nss_module_list_lock);
143 return true;
144}
145
ee5ed999
FW
146/* Loads the built-in nss_files module. */
147static bool
148module_load_nss_files (struct nss_module *module)
149{
bea1a4a7 150#if defined SHARED && defined USE_NSCD
ee5ed999
FW
151 if (is_nscd)
152 {
153 void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
ee5ed999 154 PTR_DEMANGLE (cb);
ee5ed999
FW
155 _nss_files_init (cb);
156 }
157#endif
158 return module_load_builtin (module, __nss_files_functions);
159}
160
161/* Loads the built-in nss_dns module. */
162static bool
163module_load_nss_dns (struct nss_module *module)
164{
165 return module_load_builtin (module, __nss_dns_functions);
166}
167
171689da
FW
168/* Internal implementation of __nss_module_load. */
169static bool
170module_load (struct nss_module *module)
171{
f9c8b11e
FW
172 if (strcmp (module->name, "files") == 0)
173 return module_load_nss_files (module);
ee5ed999
FW
174 if (strcmp (module->name, "dns") == 0)
175 return module_load_nss_dns (module);
f9c8b11e 176
171689da
FW
177 void *handle;
178 {
179 char *shlib_name;
180 if (__asprintf (&shlib_name, "libnss_%s.so%s",
181 module->name, __nss_shlib_revision) < 0)
182 /* This is definitely a temporary failure. Do not update
183 module->state. This will trigger another attempt at the next
184 call. */
185 return false;
186
187 handle = __libc_dlopen (shlib_name);
188 free (shlib_name);
189 }
190
191 /* Failing to load the module can be caused by several different
192 scenarios. One such scenario is that the module has been removed
193 from the disk. In which case the in-memory version is all that
194 we have, and if the module->state indidates it is loaded then we
195 can use it. */
196 if (handle == NULL)
197 {
198 /* dlopen failure. We do not know if this a temporary or
199 permanent error. See bug 22041. Update the state using the
200 double-checked locking idiom. */
201
202 __libc_lock_lock (nss_module_list_lock);
203 bool result = result;
204 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
205 {
206 case nss_module_uninitialized:
207 atomic_store_release (&module->state, nss_module_failed);
208 result = false;
209 break;
210 case nss_module_loaded:
211 result = true;
212 break;
213 case nss_module_failed:
214 result = false;
215 break;
216 }
217 __libc_lock_unlock (nss_module_list_lock);
218 return result;
219 }
220
221 nss_module_functions_untyped pointers;
222
223 /* Look up and store locally all the function pointers we may need
224 later. Doing this now means the data will not change in the
225 future. */
226 for (size_t idx = 0; idx < array_length (nss_function_name_array); ++idx)
227 {
228 char *function_name;
229 if (__asprintf (&function_name, "_nss_%s_%s",
230 module->name, nss_function_name_array[idx]) < 0)
231 {
232 /* Definitely a temporary error. */
233 __libc_dlclose (handle);
234 return false;
235 }
236 pointers[idx] = __libc_dlsym (handle, function_name);
237 free (function_name);
171689da 238 PTR_MANGLE (pointers[idx]);
171689da
FW
239 }
240
bea1a4a7 241# if defined SHARED && defined USE_NSCD
171689da
FW
242 if (is_nscd)
243 {
244 /* Call the init function when nscd is used. */
245 size_t initlen = (5 + strlen (module->name)
246 + strlen ("_init") + 1);
247 char init_name[initlen];
248
249 /* Construct the init function name. */
250 __stpcpy (__stpcpy (__stpcpy (init_name,
251 "_nss_"),
252 module->name),
253 "_init");
254
255 /* Find the optional init function. */
256 void (*ifct) (void (*) (size_t, struct traced_file *))
257 = __libc_dlsym (handle, init_name);
258 if (ifct != NULL)
259 {
260 void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
171689da 261 PTR_DEMANGLE (cb);
171689da
FW
262 ifct (cb);
263 }
264 }
265# endif
266
267 /* Install the function pointers, following the double-checked
268 locking idiom. Delay this after all processing, in case loading
269 the module triggers unwinding. */
270 __libc_lock_lock (nss_module_list_lock);
271 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
272 {
273 case nss_module_uninitialized:
274 case nss_module_failed:
275 memcpy (module->functions.untyped, pointers,
276 sizeof (module->functions.untyped));
277 module->handle = handle;
278 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
279 atomic_store_release (&module->state, nss_module_loaded);
280 break;
281 case nss_module_loaded:
282 /* If the module was already loaded, close our own handle. This
283 does not actually unload the modules, only the reference
284 counter is decremented for the loaded module. */
285 __libc_dlclose (handle);
286 break;
287 }
288 __libc_lock_unlock (nss_module_list_lock);
289 return true;
290}
291
292/* Force the module identified by MODULE to be loaded. We return
293 false if the module could not be loaded, true otherwise. Loading
294 the module requires looking up all the possible interface APIs and
295 caching the results. */
296bool
297__nss_module_load (struct nss_module *module)
298{
299 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
300 {
301 case nss_module_uninitialized:
302 return module_load (module);
303 case nss_module_loaded:
304 /* Loading has already succeeded. */
305 return true;
306 case nss_module_failed:
307 /* Loading previously failed. */
308 return false;
309 }
310 __builtin_unreachable ();
311}
312
313static int
314name_search (const void *left, const void *right)
315{
316 return strcmp (left, right);
317}
318
319/* Load module MODULE (if it isn't already) and return a pointer to
320 the module's implementation of NAME, otherwise return NULL on
321 failure or error. */
322void *
323__nss_module_get_function (struct nss_module *module, const char *name)
324{
9bdf92c7
FW
325 /* A successful dlopen might clobber errno. */
326 int saved_errno = errno;
327
171689da 328 if (!__nss_module_load (module))
9bdf92c7
FW
329 {
330 /* Reporting module load failure is currently inaccurate. See
331 bug 22041. Not changing errno is the conservative choice. */
332 __set_errno (saved_errno);
333 return NULL;
334 }
335
336 __set_errno (saved_errno);
171689da
FW
337
338 function_name *name_entry = bsearch (name, nss_function_name_array,
339 array_length (nss_function_name_array),
340 sizeof (function_name), name_search);
341 assert (name_entry != NULL);
342 size_t idx = name_entry - nss_function_name_array;
343 void *fptr = module->functions.untyped[idx];
171689da 344 PTR_DEMANGLE (fptr);
171689da
FW
345 return fptr;
346}
347
f8847d83
DD
348#if defined SHARED && defined USE_NSCD
349/* Load all libraries for the service. */
350static void
9b456c5d 351nss_load_all_libraries (enum nss_database service)
f8847d83
DD
352{
353 nss_action_list ni = NULL;
354
9b456c5d 355 if (__nss_database_get (service, &ni))
f8847d83
DD
356 while (ni->module != NULL)
357 {
358 __nss_module_load (ni->module);
359 ++ni;
360 }
361}
362
363define_traced_file (pwd, _PATH_NSSWITCH_CONF);
364define_traced_file (grp, _PATH_NSSWITCH_CONF);
365define_traced_file (hst, _PATH_NSSWITCH_CONF);
366define_traced_file (serv, _PATH_NSSWITCH_CONF);
367define_traced_file (netgr, _PATH_NSSWITCH_CONF);
368
369/* Called by nscd and nscd alone. */
370void
371__nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
372{
373 void (*cb1) (size_t, struct traced_file *);
374 cb1 = cb;
f8847d83 375 PTR_MANGLE (cb);
f8847d83
DD
376 nscd_init_cb = cb;
377 is_nscd = true;
378
379 /* Find all the relevant modules so that the init functions are called. */
9b456c5d
DD
380 nss_load_all_libraries (nss_database_passwd);
381 nss_load_all_libraries (nss_database_group);
382 nss_load_all_libraries (nss_database_hosts);
383 nss_load_all_libraries (nss_database_services);
f8847d83
DD
384
385 /* Make sure NSCD purges its cache if nsswitch.conf changes. */
386 init_traced_file (&pwd_traced_file.file, _PATH_NSSWITCH_CONF, 0);
387 cb1 (pwddb, &pwd_traced_file.file);
388 init_traced_file (&grp_traced_file.file, _PATH_NSSWITCH_CONF, 0);
389 cb1 (grpdb, &grp_traced_file.file);
390 init_traced_file (&hst_traced_file.file, _PATH_NSSWITCH_CONF, 0);
391 cb1 (hstdb, &hst_traced_file.file);
392 init_traced_file (&serv_traced_file.file, _PATH_NSSWITCH_CONF, 0);
393 cb1 (servdb, &serv_traced_file.file);
394 init_traced_file (&netgr_traced_file.file, _PATH_NSSWITCH_CONF, 0);
395 cb1 (netgrdb, &netgr_traced_file.file);
396
397 /* Disable all uses of NSCD. */
398 __nss_not_use_nscd_passwd = -1;
399 __nss_not_use_nscd_group = -1;
400 __nss_not_use_nscd_hosts = -1;
401 __nss_not_use_nscd_services = -1;
402 __nss_not_use_nscd_netgroup = -1;
403}
404#endif
405
429029a7
DD
406/* Block attempts to dlopen any module we haven't already opened. */
407void
408__nss_module_disable_loading (void)
409{
410 __libc_lock_lock (nss_module_list_lock);
411
412 for (struct nss_module *p = nss_module_list; p != NULL; p = p->next)
413 if (p->state == nss_module_uninitialized)
414 p->state = nss_module_failed;
415
416 __libc_lock_unlock (nss_module_list_lock);
417}
418
88677348 419void
171689da
FW
420__nss_module_freeres (void)
421{
422 struct nss_module *current = nss_module_list;
423 while (current != NULL)
424 {
ee5ed999
FW
425 /* Ignore built-in modules (which have a NULL handle). */
426 if (current->state == nss_module_loaded
427 && current->handle != NULL)
171689da
FW
428 __libc_dlclose (current->handle);
429
430 struct nss_module *next = current->next;
431 free (current);
432 current = next;
433 }
434 nss_module_list = NULL;
435}
This page took 0.142526 seconds and 5 git commands to generate.