1 /* Global list of NSS service modules.
2 Copyright (c) 2020-2023 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>
35 #include <pointer_guard.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 SHARED && defined USE_NSCD
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
);
131 for (int i
= 0; i
< nss_module_functions_count
; ++i
)
132 PTR_MANGLE (module
->functions
.untyped
[i
]);
134 module
->handle
= NULL
;
135 /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */
136 atomic_store_release (&module
->state
, nss_module_loaded
);
138 case nss_module_loaded
:
139 /* Nothing to clean up. */
142 __libc_lock_unlock (nss_module_list_lock
);
146 /* Loads the built-in nss_files module. */
148 module_load_nss_files (struct nss_module
*module
)
150 #if defined SHARED && defined USE_NSCD
153 void (*cb
) (size_t, struct traced_file
*) = nscd_init_cb
;
155 _nss_files_init (cb
);
158 return module_load_builtin (module
, __nss_files_functions
);
161 /* Loads the built-in nss_dns module. */
163 module_load_nss_dns (struct nss_module
*module
)
165 return module_load_builtin (module
, __nss_dns_functions
);
168 /* Internal implementation of __nss_module_load. */
170 module_load (struct nss_module
*module
)
172 if (strcmp (module
->name
, "files") == 0)
173 return module_load_nss_files (module
);
174 if (strcmp (module
->name
, "dns") == 0)
175 return module_load_nss_dns (module
);
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
187 handle
= __libc_dlopen (shlib_name
);
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
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. */
202 __libc_lock_lock (nss_module_list_lock
);
203 bool result
= result
;
204 switch ((enum nss_module_state
) atomic_load_acquire (&module
->state
))
206 case nss_module_uninitialized
:
207 atomic_store_release (&module
->state
, nss_module_failed
);
210 case nss_module_loaded
:
213 case nss_module_failed
:
217 __libc_lock_unlock (nss_module_list_lock
);
221 nss_module_functions_untyped pointers
;
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
226 for (size_t idx
= 0; idx
< array_length (nss_function_name_array
); ++idx
)
229 if (__asprintf (&function_name
, "_nss_%s_%s",
230 module
->name
, nss_function_name_array
[idx
]) < 0)
232 /* Definitely a temporary error. */
233 __libc_dlclose (handle
);
236 pointers
[idx
] = __libc_dlsym (handle
, function_name
);
237 free (function_name
);
238 PTR_MANGLE (pointers
[idx
]);
241 # if defined SHARED && defined USE_NSCD
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
];
249 /* Construct the init function name. */
250 __stpcpy (__stpcpy (__stpcpy (init_name
,
255 /* Find the optional init function. */
256 void (*ifct
) (void (*) (size_t, struct traced_file
*))
257 = __libc_dlsym (handle
, init_name
);
260 void (*cb
) (size_t, struct traced_file
*) = nscd_init_cb
;
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
))
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
);
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
);
288 __libc_lock_unlock (nss_module_list_lock
);
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. */
297 __nss_module_load (struct nss_module
*module
)
299 switch ((enum nss_module_state
) atomic_load_acquire (&module
->state
))
301 case nss_module_uninitialized
:
302 return module_load (module
);
303 case nss_module_loaded
:
304 /* Loading has already succeeded. */
306 case nss_module_failed
:
307 /* Loading previously failed. */
310 __builtin_unreachable ();
314 name_search (const void *left
, const void *right
)
316 return strcmp (left
, right
);
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
323 __nss_module_get_function (struct nss_module
*module
, const char *name
)
325 /* A successful dlopen might clobber errno. */
326 int saved_errno
= errno
;
328 if (!__nss_module_load (module
))
330 /* Reporting module load failure is currently inaccurate. See
331 bug 22041. Not changing errno is the conservative choice. */
332 __set_errno (saved_errno
);
336 __set_errno (saved_errno
);
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
];
348 #if defined SHARED && defined USE_NSCD
349 /* Load all libraries for the service. */
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
);
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. */
371 __nss_disable_nscd (void (*cb
) (size_t, struct traced_file
*))
373 void (*cb1
) (size_t, struct traced_file
*);
379 /* Find all the relevant modules so that the init functions are called. */
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
);
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
);
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;
406 /* Block attempts to dlopen any module we haven't already opened. */
408 __nss_module_disable_loading (void)
410 __libc_lock_lock (nss_module_list_lock
);
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
;
416 __libc_lock_unlock (nss_module_list_lock
);
420 __nss_module_freeres (void)
422 struct nss_module
*current
= nss_module_list
;
423 while (current
!= NULL
)
425 /* Ignore built-in modules (which have a NULL handle). */
426 if (current
->state
== nss_module_loaded
427 && current
->handle
!= NULL
)
428 __libc_dlclose (current
->handle
);
430 struct nss_module
*next
= current
->next
;
434 nss_module_list
= NULL
;