mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-30 22:43:12 +03:00
nss: Implement <nss_database.h>
This code manages the mappings of the available databases in NSS (i.e. passwd, hosts, netgroup, etc) with the actions that should be taken to do a query on those databases. This is the main API between query functions scattered throughout glibc and the underlying code (actions, modules, etc). Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
This commit is contained in:
committed by
DJ Delorie
parent
fd5b9b4458
commit
fa78feca47
@ -31,7 +31,7 @@ routines = nsswitch getnssent getnssent_r digits_dots \
|
|||||||
compat-lookup nss_hash nss_files_fopen \
|
compat-lookup nss_hash nss_files_fopen \
|
||||||
nss_readline nss_parse_line_result \
|
nss_readline nss_parse_line_result \
|
||||||
nss_fgetent_r nss_module nss_action \
|
nss_fgetent_r nss_module nss_action \
|
||||||
nss_action_parse
|
nss_action_parse nss_database
|
||||||
|
|
||||||
# These are the databases that go through nss dispatch.
|
# These are the databases that go through nss dispatch.
|
||||||
# Caution: if you add a database here, you must add its real name
|
# Caution: if you add a database here, you must add its real name
|
||||||
|
433
nss/nss_database.c
Normal file
433
nss/nss_database.c
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
/* Mapping NSS services to action lists.
|
||||||
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "nss_database.h"
|
||||||
|
|
||||||
|
#include <allocate_once.h>
|
||||||
|
#include <array_length.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <atomic.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <file_change_detection.h>
|
||||||
|
#include <libc-lock.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio_ext.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct nss_database_state
|
||||||
|
{
|
||||||
|
struct nss_database_data data;
|
||||||
|
__libc_lock_define (, lock);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Global NSS database state. Underlying type is "struct
|
||||||
|
nss_database_state *" but the allocate_once API requires
|
||||||
|
"void *". */
|
||||||
|
static void *global_database_state;
|
||||||
|
|
||||||
|
/* Allocate and return pointer to nss_database_state object or
|
||||||
|
on failure return NULL. */
|
||||||
|
static void *
|
||||||
|
global_state_allocate (void *closure)
|
||||||
|
{
|
||||||
|
struct nss_database_state *result = malloc (sizeof (*result));
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
result->data.nsswitch_conf.size = -1; /* Force reload. */
|
||||||
|
memset (result->data.services, 0, sizeof (result->data.services));
|
||||||
|
result->data.initialized = true;
|
||||||
|
result->data.reload_disabled = false;
|
||||||
|
__libc_lock_init (result->lock);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return pointer to global NSS database state, allocating as
|
||||||
|
required, or returning NULL on failure. */
|
||||||
|
static struct nss_database_state *
|
||||||
|
nss_database_state_get (void)
|
||||||
|
{
|
||||||
|
return allocate_once (&global_database_state, global_state_allocate,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Database default selections. nis/compat mappings get turned into
|
||||||
|
"files" for !LINK_OBSOLETE_NSL configurations. */
|
||||||
|
enum nss_database_default
|
||||||
|
{
|
||||||
|
nss_database_default_defconfig = 0, /* "nis [NOTFOUND=return] files". */
|
||||||
|
nss_database_default_compat, /* "compat [NOTFOUND=return] files". */
|
||||||
|
nss_database_default_dns, /* "dns [!UNAVAIL=return] files". */
|
||||||
|
nss_database_default_files, /* "files". */
|
||||||
|
nss_database_default_nis, /* "nis". */
|
||||||
|
nss_database_default_nis_nisplus, /* "nis nisplus". */
|
||||||
|
nss_database_default_none, /* Empty list. */
|
||||||
|
|
||||||
|
NSS_DATABASE_DEFAULT_COUNT /* Number of defaults. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Databases not listed default to nss_database_default_defconfig. */
|
||||||
|
static const char per_database_defaults[NSS_DATABASE_COUNT] =
|
||||||
|
{
|
||||||
|
[nss_database_group] = nss_database_default_compat,
|
||||||
|
[nss_database_gshadow] = nss_database_default_files,
|
||||||
|
[nss_database_hosts] = nss_database_default_dns,
|
||||||
|
[nss_database_initgroups] = nss_database_default_none,
|
||||||
|
[nss_database_networks] = nss_database_default_dns,
|
||||||
|
[nss_database_passwd] = nss_database_default_compat,
|
||||||
|
[nss_database_publickey] = nss_database_default_nis_nisplus,
|
||||||
|
[nss_database_shadow] = nss_database_default_compat,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nss_database_default_cache
|
||||||
|
{
|
||||||
|
nss_action_list caches[NSS_DATABASE_DEFAULT_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nss_database_select_default (struct nss_database_default_cache *cache,
|
||||||
|
enum nss_database db, nss_action_list *result)
|
||||||
|
{
|
||||||
|
enum nss_database_default def = per_database_defaults[db];
|
||||||
|
*result = cache->caches[def];
|
||||||
|
if (*result != NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Determine the default line string. */
|
||||||
|
const char *line;
|
||||||
|
switch (def)
|
||||||
|
{
|
||||||
|
#ifdef LINK_OBSOLETE_NSL
|
||||||
|
case nss_database_default_defconfig:
|
||||||
|
line = "nis [NOTFOUND=return] files";
|
||||||
|
break;
|
||||||
|
case nss_database_default_compat:
|
||||||
|
line = "compat [NOTFOUND=return] files";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case nss_database_default_dns:
|
||||||
|
line = "dns [!UNAVAIL=return] files";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nss_database_default_files:
|
||||||
|
#ifndef LINK_OBSOLETE_NSL
|
||||||
|
case nss_database_default_defconfig:
|
||||||
|
case nss_database_default_compat:
|
||||||
|
#endif
|
||||||
|
line = "files";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nss_database_default_nis:
|
||||||
|
line = "nis";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nss_database_default_nis_nisplus:
|
||||||
|
line = "nis nisplus";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nss_database_default_none:
|
||||||
|
/* Very special case: Leave *result as NULL. */
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case NSS_DATABASE_DEFAULT_COUNT:
|
||||||
|
__builtin_unreachable ();
|
||||||
|
}
|
||||||
|
if (def < 0 || def >= NSS_DATABASE_DEFAULT_COUNT)
|
||||||
|
/* Tell GCC that line is initialized. */
|
||||||
|
__builtin_unreachable ();
|
||||||
|
|
||||||
|
*result = __nss_action_parse (line);
|
||||||
|
if (*result == NULL)
|
||||||
|
{
|
||||||
|
assert (errno == ENOMEM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* database_name must be large enough for each individual name plus a
|
||||||
|
null terminator. */
|
||||||
|
typedef char database_name[11];
|
||||||
|
#define DEFINE_DATABASE(name) \
|
||||||
|
_Static_assert (sizeof (#name) <= sizeof (database_name), #name);
|
||||||
|
#include "databases.def"
|
||||||
|
#undef DEFINE_DATABASE
|
||||||
|
|
||||||
|
static const database_name nss_database_name_array[] =
|
||||||
|
{
|
||||||
|
#define DEFINE_DATABASE(name) #name,
|
||||||
|
#include "databases.def"
|
||||||
|
#undef DEFINE_DATABASE
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
name_search (const void *left, const void *right)
|
||||||
|
{
|
||||||
|
return strcmp (left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
name_to_database_index (const char *name)
|
||||||
|
{
|
||||||
|
database_name *name_entry = bsearch (name, nss_database_name_array,
|
||||||
|
array_length (nss_database_name_array),
|
||||||
|
sizeof (database_name), name_search);
|
||||||
|
if (name_entry == NULL)
|
||||||
|
return -1;
|
||||||
|
return name_entry - nss_database_name_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
process_line (struct nss_database_data *data, char *line)
|
||||||
|
{
|
||||||
|
/* Ignore leading white spaces. ATTENTION: this is different from
|
||||||
|
what is implemented in Solaris. The Solaris man page says a line
|
||||||
|
beginning with a white space character is ignored. We regard
|
||||||
|
this as just another misfeature in Solaris. */
|
||||||
|
while (isspace (line[0]))
|
||||||
|
++line;
|
||||||
|
|
||||||
|
/* Recognize `<database> ":"'. */
|
||||||
|
char *name = line;
|
||||||
|
while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
|
||||||
|
++line;
|
||||||
|
if (line[0] == '\0' || name == line)
|
||||||
|
/* Syntax error. Skip this line. */
|
||||||
|
return true;
|
||||||
|
*line++ = '\0';
|
||||||
|
|
||||||
|
int db = name_to_database_index (name);
|
||||||
|
if (db < 0)
|
||||||
|
/* Not our database e.g. sudoers, automount, etc. */
|
||||||
|
return true;
|
||||||
|
|
||||||
|
nss_action_list result = __nss_action_parse (line);
|
||||||
|
if (result == NULL)
|
||||||
|
return false;
|
||||||
|
data->services[db] = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate over the lines in FP, parse them, and store them in DATA.
|
||||||
|
Return false on memory allocation failure, true on success. */
|
||||||
|
static bool
|
||||||
|
nss_database_reload_1 (struct nss_database_data *data, FILE *fp)
|
||||||
|
{
|
||||||
|
char *line = NULL;
|
||||||
|
size_t line_allocated = 0;
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
ssize_t ret = __getline (&line, &line_allocated, fp);
|
||||||
|
if (ferror_unlocked (fp))
|
||||||
|
break;
|
||||||
|
if (feof_unlocked (fp))
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert (ret > 0);
|
||||||
|
(void) ret; /* For NDEBUG builds. */
|
||||||
|
|
||||||
|
if (!process_line (data, line))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (line);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nss_database_reload (struct nss_database_data *staging,
|
||||||
|
struct file_change_detection *initial)
|
||||||
|
{
|
||||||
|
FILE *fp = fopen (_PATH_NSSWITCH_CONF, "rce");
|
||||||
|
if (fp == NULL)
|
||||||
|
switch (errno)
|
||||||
|
{
|
||||||
|
case EACCES:
|
||||||
|
case EISDIR:
|
||||||
|
case ELOOP:
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
case EPERM:
|
||||||
|
/* Ignore these errors. They are persistent errors caused
|
||||||
|
by file system contents. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Other errors refer to resource allocation problems and
|
||||||
|
need to be handled by the application. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* No other threads have access to fp. */
|
||||||
|
__fsetlocking (fp, FSETLOCKING_BYCALLER);
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
if (fp != NULL)
|
||||||
|
ok = nss_database_reload_1 (staging, fp);
|
||||||
|
|
||||||
|
/* Apply defaults. */
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
struct nss_database_default_cache cache = { };
|
||||||
|
for (int i = 0; i < NSS_DATABASE_COUNT; ++i)
|
||||||
|
if (staging->services[i] == NULL)
|
||||||
|
{
|
||||||
|
ok = nss_database_select_default (&cache, i,
|
||||||
|
&staging->services[i]);
|
||||||
|
if (!ok)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
ok = __file_change_detection_for_fp (&staging->nsswitch_conf, fp);
|
||||||
|
|
||||||
|
if (fp != NULL)
|
||||||
|
{
|
||||||
|
int saved_errno = errno;
|
||||||
|
fclose (fp);
|
||||||
|
__set_errno (saved_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && !__file_is_unchanged (&staging->nsswitch_conf, initial))
|
||||||
|
/* Reload is required because the file changed while reading. */
|
||||||
|
staging->nsswitch_conf.size = -1;
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nss_database_check_reload_and_get (struct nss_database_state *local,
|
||||||
|
nss_action_list *result,
|
||||||
|
enum nss_database database_index)
|
||||||
|
{
|
||||||
|
/* Acquire MO is needed because the thread that sets reload_disabled
|
||||||
|
may have loaded the configuration first, so synchronize with the
|
||||||
|
Release MO store there. */
|
||||||
|
if (atomic_load_acquire (&local->data.reload_disabled))
|
||||||
|
/* No reload, so there is no error. */
|
||||||
|
return true;
|
||||||
|
|
||||||
|
struct file_change_detection initial;
|
||||||
|
if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__libc_lock_lock (local->lock);
|
||||||
|
if (__file_is_unchanged (&initial, &local->data.nsswitch_conf))
|
||||||
|
{
|
||||||
|
/* Configuration is up-to-date. Read it and return it to the
|
||||||
|
caller. */
|
||||||
|
*result = local->data.services[database_index];
|
||||||
|
__libc_lock_unlock (local->lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
__libc_lock_unlock (local->lock);
|
||||||
|
|
||||||
|
/* Avoid overwriting the global configuration until we have loaded
|
||||||
|
everything successfully. Otherwise, if the file change
|
||||||
|
information changes back to what is in the global configuration,
|
||||||
|
the lookups would use the partially-written configuration. */
|
||||||
|
struct nss_database_data staging = { .initialized = true, };
|
||||||
|
|
||||||
|
bool ok = nss_database_reload (&staging, &initial);
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
__libc_lock_lock (local->lock);
|
||||||
|
|
||||||
|
/* See above for memory order. */
|
||||||
|
if (!atomic_load_acquire (&local->data.reload_disabled))
|
||||||
|
/* This may go back in time if another thread beats this
|
||||||
|
thread with the update, but in this case, a reload happens
|
||||||
|
on the next NSS call. */
|
||||||
|
local->data = staging;
|
||||||
|
|
||||||
|
*result = local->data.services[database_index];
|
||||||
|
__libc_lock_unlock (local->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
__nss_database_get (enum nss_database db, nss_action_list *actions)
|
||||||
|
{
|
||||||
|
struct nss_database_state *local = nss_database_state_get ();
|
||||||
|
return nss_database_check_reload_and_get (local, actions, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
nss_action_list
|
||||||
|
__nss_database_get_noreload (enum nss_database db)
|
||||||
|
{
|
||||||
|
/* There must have been a previous __nss_database_get call. */
|
||||||
|
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||||||
|
assert (local != NULL);
|
||||||
|
|
||||||
|
__libc_lock_lock (local->lock);
|
||||||
|
nss_action_list result = local->data.services[db];
|
||||||
|
__libc_lock_unlock (local->lock);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_freeres_fn_section
|
||||||
|
__nss_database_freeres (void)
|
||||||
|
{
|
||||||
|
free (global_database_state);
|
||||||
|
global_database_state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||||||
|
{
|
||||||
|
/* Do not use allocate_once to trigger loading unnecessarily. */
|
||||||
|
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||||||
|
if (local == NULL)
|
||||||
|
data->initialized = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Make a copy of the configuration. This approach was chosen
|
||||||
|
because it avoids acquiring the lock during the actual
|
||||||
|
fork. */
|
||||||
|
__libc_lock_lock (local->lock);
|
||||||
|
*data = local->data;
|
||||||
|
__libc_lock_unlock (local->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__nss_database_fork_subprocess (struct nss_database_data *data)
|
||||||
|
{
|
||||||
|
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||||||
|
if (data->initialized)
|
||||||
|
{
|
||||||
|
/* Restore the state at the point of the fork. */
|
||||||
|
assert (local != NULL);
|
||||||
|
local->data = *data;
|
||||||
|
__libc_lock_init (local->lock);
|
||||||
|
}
|
||||||
|
else if (local != NULL)
|
||||||
|
/* The NSS configuration was loaded concurrently during fork. We
|
||||||
|
do not know its state, so we need to discard it. */
|
||||||
|
global_database_state = NULL;
|
||||||
|
}
|
88
nss/nss_database.h
Normal file
88
nss/nss_database.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/* Mapping NSS services to action lists.
|
||||||
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _NSS_DATABASE_H
|
||||||
|
#define _NSS_DATABASE_H
|
||||||
|
|
||||||
|
#include <file_change_detection.h>
|
||||||
|
|
||||||
|
/* Each "line" in nsswitch.conf maps a supported database (example:
|
||||||
|
passwd) to one or more name service providers (example: files dns).
|
||||||
|
Internally, each name service provider (example: dns) is a
|
||||||
|
dynamically loadable module (i.e. libnss_dns.so), managed by
|
||||||
|
nss_module.h. The sequence of providers and rules (example: files
|
||||||
|
[SUCCESS=RETURN] dns) is mapped by nss_action.h to a cached entry
|
||||||
|
which encodes the sequence of modules and rules. Keeping track of
|
||||||
|
all supported databases and their corresponding actions is done
|
||||||
|
here.
|
||||||
|
|
||||||
|
The key entry is __nss_database_get, which provides a set of
|
||||||
|
actions which can be used with nss_lookup_function() and
|
||||||
|
nss_next(). Callers should assume that these functions are fast,
|
||||||
|
and should not cache the result longer than needed. */
|
||||||
|
|
||||||
|
#include "nss_action.h"
|
||||||
|
|
||||||
|
/* The enumeration literal in enum nss_database for the database NAME
|
||||||
|
(e.g., nss_database_hosts for hosts). */
|
||||||
|
#define NSS_DATABASE_LITERAL(name) nss_database_##name
|
||||||
|
|
||||||
|
enum nss_database
|
||||||
|
{
|
||||||
|
#define DEFINE_DATABASE(name) NSS_DATABASE_LITERAL (name),
|
||||||
|
#include "databases.def"
|
||||||
|
#undef DEFINE_DATABASE
|
||||||
|
|
||||||
|
/* Total number of databases. */
|
||||||
|
NSS_DATABASE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Looks up the action list for DB and stores it in *ACTIONS. Returns
|
||||||
|
true on success or false on failure. Success can mean that
|
||||||
|
*ACTIONS is NULL. */
|
||||||
|
bool __nss_database_get (enum nss_database db, nss_action_list *actions)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
/* Like __nss_database_get, but does not reload /etc/nsswitch.conf
|
||||||
|
from disk. This assumes that there has been a previous successful
|
||||||
|
__nss_database_get call (which may not have returned any data). */
|
||||||
|
nss_action_list __nss_database_get_noreload (enum nss_database db)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
/* Called from __libc_freeres. */
|
||||||
|
void __nss_database_freeres (void) attribute_hidden;
|
||||||
|
|
||||||
|
/* Internal type. Exposed only for fork handling purposes. */
|
||||||
|
struct nss_database_data
|
||||||
|
{
|
||||||
|
struct file_change_detection nsswitch_conf;
|
||||||
|
nss_action_list services[NSS_DATABASE_COUNT];
|
||||||
|
int reload_disabled; /* Actually bool; int for atomic access. */
|
||||||
|
bool initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Called by fork in the parent process, before forking. */
|
||||||
|
void __nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
/* Called by fork in the new subprocess, after forking. */
|
||||||
|
void __nss_database_fork_subprocess (struct nss_database_data *data)
|
||||||
|
attribute_hidden;
|
||||||
|
|
||||||
|
#endif /* _NSS_DATABASE_H */
|
@ -28,6 +28,7 @@
|
|||||||
#include "hurdmalloc.h" /* XXX */
|
#include "hurdmalloc.h" /* XXX */
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
#include <malloc/malloc-internal.h>
|
#include <malloc/malloc-internal.h>
|
||||||
|
#include <nss/nss_database.h>
|
||||||
|
|
||||||
#undef __fork
|
#undef __fork
|
||||||
|
|
||||||
@ -68,6 +69,7 @@ __fork (void)
|
|||||||
size_t i;
|
size_t i;
|
||||||
error_t err;
|
error_t err;
|
||||||
struct hurd_sigstate *volatile ss;
|
struct hurd_sigstate *volatile ss;
|
||||||
|
struct nss_database_data nss_database_data;
|
||||||
|
|
||||||
RUN_HOOK (_hurd_atfork_prepare_hook, ());
|
RUN_HOOK (_hurd_atfork_prepare_hook, ());
|
||||||
|
|
||||||
@ -109,6 +111,9 @@ __fork (void)
|
|||||||
/* Run things that prepare for forking before we create the task. */
|
/* Run things that prepare for forking before we create the task. */
|
||||||
RUN_HOOK (_hurd_fork_prepare_hook, ());
|
RUN_HOOK (_hurd_fork_prepare_hook, ());
|
||||||
|
|
||||||
|
call_function_static_weak (__nss_database_fork_prepare_parent,
|
||||||
|
&nss_database_data);
|
||||||
|
|
||||||
/* Lock things that want to be locked before we fork. */
|
/* Lock things that want to be locked before we fork. */
|
||||||
{
|
{
|
||||||
void *const *p;
|
void *const *p;
|
||||||
@ -666,6 +671,9 @@ __fork (void)
|
|||||||
_hurd_malloc_fork_child ();
|
_hurd_malloc_fork_child ();
|
||||||
call_function_static_weak (__malloc_fork_unlock_child);
|
call_function_static_weak (__malloc_fork_unlock_child);
|
||||||
|
|
||||||
|
call_function_static_weak (__nss_database_fork_subprocess,
|
||||||
|
&nss_database_data);
|
||||||
|
|
||||||
/* Run things that want to run in the child task to set up. */
|
/* Run things that want to run in the child task to set up. */
|
||||||
RUN_HOOK (_hurd_fork_child_hook, ());
|
RUN_HOOK (_hurd_fork_child_hook, ());
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <arch-fork.h>
|
#include <arch-fork.h>
|
||||||
#include <futex-internal.h>
|
#include <futex-internal.h>
|
||||||
#include <malloc/malloc-internal.h>
|
#include <malloc/malloc-internal.h>
|
||||||
|
#include <nss/nss_database.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fresetlockfiles (void)
|
fresetlockfiles (void)
|
||||||
@ -57,6 +58,8 @@ __libc_fork (void)
|
|||||||
|
|
||||||
__run_fork_handlers (atfork_run_prepare, multiple_threads);
|
__run_fork_handlers (atfork_run_prepare, multiple_threads);
|
||||||
|
|
||||||
|
struct nss_database_data nss_database_data;
|
||||||
|
|
||||||
/* If we are not running multiple threads, we do not have to
|
/* If we are not running multiple threads, we do not have to
|
||||||
preserve lock state. If fork runs from a signal handler, only
|
preserve lock state. If fork runs from a signal handler, only
|
||||||
async-signal-safe functions can be used in the child. These data
|
async-signal-safe functions can be used in the child. These data
|
||||||
@ -64,6 +67,9 @@ __libc_fork (void)
|
|||||||
not matter if fork was called from a signal handler. */
|
not matter if fork was called from a signal handler. */
|
||||||
if (multiple_threads)
|
if (multiple_threads)
|
||||||
{
|
{
|
||||||
|
call_function_static_weak (__nss_database_fork_prepare_parent,
|
||||||
|
&nss_database_data);
|
||||||
|
|
||||||
_IO_list_lock ();
|
_IO_list_lock ();
|
||||||
|
|
||||||
/* Acquire malloc locks. This needs to come last because fork
|
/* Acquire malloc locks. This needs to come last because fork
|
||||||
@ -118,6 +124,9 @@ __libc_fork (void)
|
|||||||
|
|
||||||
/* Reset locks in the I/O code. */
|
/* Reset locks in the I/O code. */
|
||||||
_IO_list_resetlock ();
|
_IO_list_resetlock ();
|
||||||
|
|
||||||
|
call_function_static_weak (__nss_database_fork_subprocess,
|
||||||
|
&nss_database_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the lock the dynamic loader uses to protect its data. */
|
/* Reset the lock the dynamic loader uses to protect its data. */
|
||||||
|
Reference in New Issue
Block a user