Enable support for GCC 11 -Wmismatched-dealloc.
[glibc.git] / nss / nss_module.c
blob60c070c8510f8a892272284a74e95f25cca78d05
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 <stddef.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 /* Suffix after .so of NSS service modules. This is a bit of magic,
35 but we assume LIBNSS_FILES_SO looks like "libnss_files.so.2" and we
36 want a pointer to the ".2" part. We have no API to extract this
37 except through the auto-generated lib-names.h and some static
38 pointer manipulation. The "-1" accounts for the trailing NUL
39 included in the sizeof. */
40 static const char *const __nss_shlib_revision
41 = LIBNSS_FILES_SO + sizeof("libnss_files.so") - 1;
43 /* A single-linked list used to implement a mapping from service names
44 to NSS modules. (Most systems only use five or so modules, so a
45 list is sufficient here.) Elements of this list are never freed
46 during normal operation. */
47 static struct nss_module *nss_module_list;
49 /* Covers the list and also loading of individual NSS service
50 modules. */
51 __libc_lock_define (static, nss_module_list_lock);
53 #if defined USE_NSCD && (!defined DO_STATIC_NSS || defined SHARED)
54 /* Nonzero if this is the nscd process. */
55 static bool is_nscd;
56 /* The callback passed to the init functions when nscd is used. */
57 static void (*nscd_init_cb) (size_t, struct traced_file *);
58 #endif
60 /* Allocate the service NAME with length NAME_LENGTH. If the service
61 is already allocated in the nss_module_list cache then we return a
62 pointer to the struct nss_module, otherwise we try to allocate a
63 new struct nss_module entry and add it to the global
64 nss_modules_list cache. If we fail to allocate the entry we return
65 NULL. Failure to allocate the entry is always transient. */
66 struct nss_module *
67 __nss_module_allocate (const char *name, size_t name_length)
69 __libc_lock_lock (nss_module_list_lock);
71 struct nss_module *result = NULL;
72 for (struct nss_module *p = nss_module_list; p != NULL; p = p->next)
73 if (strncmp (p->name, name, name_length) == 0
74 && p->name[name_length] == '\0')
76 /* Return the previously existing object. */
77 result = p;
78 break;
81 if (result == NULL)
83 /* Allocate a new list entry if the name was not found in the
84 list. */
85 result = malloc (sizeof (*result) + name_length + 1);
86 if (result != NULL)
88 result->state = nss_module_uninitialized;
89 memcpy (result->name, name, name_length);
90 result->name[name_length] = '\0';
91 result->handle = NULL;
92 result->next = nss_module_list;
93 nss_module_list = result;
97 __libc_lock_unlock (nss_module_list_lock);
98 return result;
101 /* Long enough to store the name of any function in the
102 nss_function_name_array list below, as getprotobynumber_r is the
103 longest entry in that list. */
104 typedef char function_name[sizeof("getprotobynumber_r")];
106 static const function_name nss_function_name_array[] =
108 #undef DEFINE_NSS_FUNCTION
109 #define DEFINE_NSS_FUNCTION(x) #x,
110 #include "function.def"
113 /* Internal implementation of __nss_module_load. */
114 static bool
115 module_load (struct nss_module *module)
117 void *handle;
119 char *shlib_name;
120 if (__asprintf (&shlib_name, "libnss_%s.so%s",
121 module->name, __nss_shlib_revision) < 0)
122 /* This is definitely a temporary failure. Do not update
123 module->state. This will trigger another attempt at the next
124 call. */
125 return false;
127 handle = __libc_dlopen (shlib_name);
128 free (shlib_name);
131 /* Failing to load the module can be caused by several different
132 scenarios. One such scenario is that the module has been removed
133 from the disk. In which case the in-memory version is all that
134 we have, and if the module->state indidates it is loaded then we
135 can use it. */
136 if (handle == NULL)
138 /* dlopen failure. We do not know if this a temporary or
139 permanent error. See bug 22041. Update the state using the
140 double-checked locking idiom. */
142 __libc_lock_lock (nss_module_list_lock);
143 bool result = result;
144 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
146 case nss_module_uninitialized:
147 atomic_store_release (&module->state, nss_module_failed);
148 result = false;
149 break;
150 case nss_module_loaded:
151 result = true;
152 break;
153 case nss_module_failed:
154 result = false;
155 break;
157 __libc_lock_unlock (nss_module_list_lock);
158 return result;
161 nss_module_functions_untyped pointers;
163 /* Look up and store locally all the function pointers we may need
164 later. Doing this now means the data will not change in the
165 future. */
166 for (size_t idx = 0; idx < array_length (nss_function_name_array); ++idx)
168 char *function_name;
169 if (__asprintf (&function_name, "_nss_%s_%s",
170 module->name, nss_function_name_array[idx]) < 0)
172 /* Definitely a temporary error. */
173 __libc_dlclose (handle);
174 return false;
176 pointers[idx] = __libc_dlsym (handle, function_name);
177 free (function_name);
178 #ifdef PTR_MANGLE
179 PTR_MANGLE (pointers[idx]);
180 #endif
183 # ifdef USE_NSCD
184 if (is_nscd)
186 /* Call the init function when nscd is used. */
187 size_t initlen = (5 + strlen (module->name)
188 + strlen ("_init") + 1);
189 char init_name[initlen];
191 /* Construct the init function name. */
192 __stpcpy (__stpcpy (__stpcpy (init_name,
193 "_nss_"),
194 module->name),
195 "_init");
197 /* Find the optional init function. */
198 void (*ifct) (void (*) (size_t, struct traced_file *))
199 = __libc_dlsym (handle, init_name);
200 if (ifct != NULL)
202 void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
203 # ifdef PTR_DEMANGLE
204 PTR_DEMANGLE (cb);
205 # endif
206 ifct (cb);
209 # endif
211 /* Install the function pointers, following the double-checked
212 locking idiom. Delay this after all processing, in case loading
213 the module triggers unwinding. */
214 __libc_lock_lock (nss_module_list_lock);
215 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
217 case nss_module_uninitialized:
218 case nss_module_failed:
219 memcpy (module->functions.untyped, pointers,
220 sizeof (module->functions.untyped));
221 module->handle = handle;
222 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
223 atomic_store_release (&module->state, nss_module_loaded);
224 break;
225 case nss_module_loaded:
226 /* If the module was already loaded, close our own handle. This
227 does not actually unload the modules, only the reference
228 counter is decremented for the loaded module. */
229 __libc_dlclose (handle);
230 break;
232 __libc_lock_unlock (nss_module_list_lock);
233 return true;
236 /* Force the module identified by MODULE to be loaded. We return
237 false if the module could not be loaded, true otherwise. Loading
238 the module requires looking up all the possible interface APIs and
239 caching the results. */
240 bool
241 __nss_module_load (struct nss_module *module)
243 switch ((enum nss_module_state) atomic_load_acquire (&module->state))
245 case nss_module_uninitialized:
246 return module_load (module);
247 case nss_module_loaded:
248 /* Loading has already succeeded. */
249 return true;
250 case nss_module_failed:
251 /* Loading previously failed. */
252 return false;
254 __builtin_unreachable ();
257 static int
258 name_search (const void *left, const void *right)
260 return strcmp (left, right);
263 /* Load module MODULE (if it isn't already) and return a pointer to
264 the module's implementation of NAME, otherwise return NULL on
265 failure or error. */
266 void *
267 __nss_module_get_function (struct nss_module *module, const char *name)
269 if (!__nss_module_load (module))
270 return NULL;
272 function_name *name_entry = bsearch (name, nss_function_name_array,
273 array_length (nss_function_name_array),
274 sizeof (function_name), name_search);
275 assert (name_entry != NULL);
276 size_t idx = name_entry - nss_function_name_array;
277 void *fptr = module->functions.untyped[idx];
278 #ifdef PTR_DEMANGLE
279 PTR_DEMANGLE (fptr);
280 #endif
281 return fptr;
284 #if defined SHARED && defined USE_NSCD
285 /* Load all libraries for the service. */
286 static void
287 nss_load_all_libraries (enum nss_database service)
289 nss_action_list ni = NULL;
291 if (__nss_database_get (service, &ni))
292 while (ni->module != NULL)
294 __nss_module_load (ni->module);
295 ++ni;
299 define_traced_file (pwd, _PATH_NSSWITCH_CONF);
300 define_traced_file (grp, _PATH_NSSWITCH_CONF);
301 define_traced_file (hst, _PATH_NSSWITCH_CONF);
302 define_traced_file (serv, _PATH_NSSWITCH_CONF);
303 define_traced_file (netgr, _PATH_NSSWITCH_CONF);
305 /* Called by nscd and nscd alone. */
306 void
307 __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
309 void (*cb1) (size_t, struct traced_file *);
310 cb1 = cb;
311 # ifdef PTR_MANGLE
312 PTR_MANGLE (cb);
313 # endif
314 nscd_init_cb = cb;
315 is_nscd = true;
317 /* Find all the relevant modules so that the init functions are called. */
318 nss_load_all_libraries (nss_database_passwd);
319 nss_load_all_libraries (nss_database_group);
320 nss_load_all_libraries (nss_database_hosts);
321 nss_load_all_libraries (nss_database_services);
323 /* Make sure NSCD purges its cache if nsswitch.conf changes. */
324 init_traced_file (&pwd_traced_file.file, _PATH_NSSWITCH_CONF, 0);
325 cb1 (pwddb, &pwd_traced_file.file);
326 init_traced_file (&grp_traced_file.file, _PATH_NSSWITCH_CONF, 0);
327 cb1 (grpdb, &grp_traced_file.file);
328 init_traced_file (&hst_traced_file.file, _PATH_NSSWITCH_CONF, 0);
329 cb1 (hstdb, &hst_traced_file.file);
330 init_traced_file (&serv_traced_file.file, _PATH_NSSWITCH_CONF, 0);
331 cb1 (servdb, &serv_traced_file.file);
332 init_traced_file (&netgr_traced_file.file, _PATH_NSSWITCH_CONF, 0);
333 cb1 (netgrdb, &netgr_traced_file.file);
335 /* Disable all uses of NSCD. */
336 __nss_not_use_nscd_passwd = -1;
337 __nss_not_use_nscd_group = -1;
338 __nss_not_use_nscd_hosts = -1;
339 __nss_not_use_nscd_services = -1;
340 __nss_not_use_nscd_netgroup = -1;
342 #endif
344 /* Block attempts to dlopen any module we haven't already opened. */
345 void
346 __nss_module_disable_loading (void)
348 __libc_lock_lock (nss_module_list_lock);
350 for (struct nss_module *p = nss_module_list; p != NULL; p = p->next)
351 if (p->state == nss_module_uninitialized)
352 p->state = nss_module_failed;
354 __libc_lock_unlock (nss_module_list_lock);
357 void __libc_freeres_fn_section
358 __nss_module_freeres (void)
360 struct nss_module *current = nss_module_list;
361 while (current != NULL)
363 if (current->state == nss_module_loaded)
364 __libc_dlclose (current->handle);
366 struct nss_module *next = current->next;
367 free (current);
368 current = next;
370 nss_module_list = NULL;