Prepare for glibc 2.34 release.
[glibc.git] / nss / nss_module.c
blobb28cb94a6a0aeb41d85413cb2663a5491894d3c9
1 /* Global list of NSS service modules.
2 Copyright (c) 2020-2021 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/>. */
19 #include <nsswitch.h>
20 #include <nscd/nscd.h>
21 #include <nscd/nscd_proto.h>
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>
29 #include <nss_dns.h>
30 #include <nss_files.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sysdep.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
53 modules. */
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. */
58 static bool is_nscd;
59 /* The callback passed to the init functions when nscd is used. */
60 static void (*nscd_init_cb) (size_t, struct traced_file *);
61 #endif
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. */
69 struct nss_module *
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. */
80 result = p;
81 break;
84 if (result == NULL)
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)
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);
101 return result;
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. */
118 static bool
119 module_load_builtin (struct nss_module *module,
120 void (*bind) (nss_module_functions_untyped))
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))
127 case nss_module_uninitialized:
128 case nss_module_failed:
129 bind (module->functions.untyped);
131 #ifdef PTR_MANGLE
132 for (int i = 0; i < nss_module_functions_count; ++i)
133 PTR_MANGLE (module->functions.untyped[i]);
134 #endif
136 module->handle = NULL;
137 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
138 atomic_store_release (&module->state, nss_module_loaded);
139 break;
140 case nss_module_loaded:
141 /* Nothing to clean up. */
142 break;
144 __libc_lock_unlock (nss_module_list_lock);
145 return true;
148 /* Loads the built-in nss_files module. */
149 static bool
150 module_load_nss_files (struct nss_module *module)
152 #ifdef USE_NSCD
153 if (is_nscd)
155 void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
156 # ifdef PTR_DEMANGLE
157 PTR_DEMANGLE (cb);
158 # endif
159 _nss_files_init (cb);
161 #endif
162 return module_load_builtin (module, __nss_files_functions);
165 /* Loads the built-in nss_dns module. */
166 static bool
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. */
173 static bool
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);
181 void *handle;
183 char *shlib_name;
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
188 call. */
189 return false;
191 handle = __libc_dlopen (shlib_name);
192 free (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
199 can use it. */
200 if (handle == NULL)
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);
212 result = false;
213 break;
214 case nss_module_loaded:
215 result = true;
216 break;
217 case nss_module_failed:
218 result = false;
219 break;
221 __libc_lock_unlock (nss_module_list_lock);
222 return result;
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
229 future. */
230 for (size_t idx = 0; idx < array_length (nss_function_name_array); ++idx)
232 char *function_name;
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);
238 return false;
240 pointers[idx] = __libc_dlsym (handle, function_name);
241 free (function_name);
242 #ifdef PTR_MANGLE
243 PTR_MANGLE (pointers[idx]);
244 #endif
247 # ifdef USE_NSCD
248 if (is_nscd)
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,
257 "_nss_"),
258 module->name),
259 "_init");
261 /* Find the optional init function. */
262 void (*ifct) (void (*) (size_t, struct traced_file *))
263 = __libc_dlsym (handle, init_name);
264 if (ifct != NULL)
266 void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
267 # ifdef PTR_DEMANGLE
268 PTR_DEMANGLE (cb);
269 # endif
270 ifct (cb);
273 # endif
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);
288 break;
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);
294 break;
296 __libc_lock_unlock (nss_module_list_lock);
297 return true;
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. */
304 bool
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. */
313 return true;
314 case nss_module_failed:
315 /* Loading previously failed. */
316 return false;
318 __builtin_unreachable ();
321 static int
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
329 failure or error. */
330 void *
331 __nss_module_get_function (struct nss_module *module, const char *name)
333 if (!__nss_module_load (module))
334 return NULL;
336 function_name *name_entry = bsearch (name, nss_function_name_array,
337 array_length (nss_function_name_array),
338 sizeof (function_name), name_search);
339 assert (name_entry != NULL);
340 size_t idx = name_entry - nss_function_name_array;
341 void *fptr = module->functions.untyped[idx];
342 #ifdef PTR_DEMANGLE
343 PTR_DEMANGLE (fptr);
344 #endif
345 return fptr;
348 #if defined SHARED && defined USE_NSCD
349 /* Load all libraries for the service. */
350 static void
351 nss_load_all_libraries (enum nss_database service)
353 nss_action_list ni = NULL;
355 if (__nss_database_get (service, &ni))
356 while (ni->module != NULL)
358 __nss_module_load (ni->module);
359 ++ni;
363 define_traced_file (pwd, _PATH_NSSWITCH_CONF);
364 define_traced_file (grp, _PATH_NSSWITCH_CONF);
365 define_traced_file (hst, _PATH_NSSWITCH_CONF);
366 define_traced_file (serv, _PATH_NSSWITCH_CONF);
367 define_traced_file (netgr, _PATH_NSSWITCH_CONF);
369 /* Called by nscd and nscd alone. */
370 void
371 __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
373 void (*cb1) (size_t, struct traced_file *);
374 cb1 = cb;
375 # ifdef PTR_MANGLE
376 PTR_MANGLE (cb);
377 # endif
378 nscd_init_cb = cb;
379 is_nscd = true;
381 /* Find all the relevant modules so that the init functions are called. */
382 nss_load_all_libraries (nss_database_passwd);
383 nss_load_all_libraries (nss_database_group);
384 nss_load_all_libraries (nss_database_hosts);
385 nss_load_all_libraries (nss_database_services);
387 /* Make sure NSCD purges its cache if nsswitch.conf changes. */
388 init_traced_file (&pwd_traced_file.file, _PATH_NSSWITCH_CONF, 0);
389 cb1 (pwddb, &pwd_traced_file.file);
390 init_traced_file (&grp_traced_file.file, _PATH_NSSWITCH_CONF, 0);
391 cb1 (grpdb, &grp_traced_file.file);
392 init_traced_file (&hst_traced_file.file, _PATH_NSSWITCH_CONF, 0);
393 cb1 (hstdb, &hst_traced_file.file);
394 init_traced_file (&serv_traced_file.file, _PATH_NSSWITCH_CONF, 0);
395 cb1 (servdb, &serv_traced_file.file);
396 init_traced_file (&netgr_traced_file.file, _PATH_NSSWITCH_CONF, 0);
397 cb1 (netgrdb, &netgr_traced_file.file);
399 /* Disable all uses of NSCD. */
400 __nss_not_use_nscd_passwd = -1;
401 __nss_not_use_nscd_group = -1;
402 __nss_not_use_nscd_hosts = -1;
403 __nss_not_use_nscd_services = -1;
404 __nss_not_use_nscd_netgroup = -1;
406 #endif
408 /* Block attempts to dlopen any module we haven't already opened. */
409 void
410 __nss_module_disable_loading (void)
412 __libc_lock_lock (nss_module_list_lock);
414 for (struct nss_module *p = nss_module_list; p != NULL; p = p->next)
415 if (p->state == nss_module_uninitialized)
416 p->state = nss_module_failed;
418 __libc_lock_unlock (nss_module_list_lock);
421 void __libc_freeres_fn_section
422 __nss_module_freeres (void)
424 struct nss_module *current = nss_module_list;
425 while (current != NULL)
427 /* Ignore built-in modules (which have a NULL handle). */
428 if (current->state == nss_module_loaded
429 && current->handle != NULL)
430 __libc_dlclose (current->handle);
432 struct nss_module *next = current->next;
433 free (current);
434 current = next;
436 nss_module_list = NULL;