(root)/
glibc-2.38/
nss/
nss_database.c
       1  /* Mapping NSS services to action lists.
       2     Copyright (C) 2020-2023 Free Software Foundation, Inc.
       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  
      19  #include "nss_database.h"
      20  
      21  #include <allocate_once.h>
      22  #include <array_length.h>
      23  #include <assert.h>
      24  #include <atomic.h>
      25  #include <ctype.h>
      26  #include <file_change_detection.h>
      27  #include <libc-lock.h>
      28  #include <netdb.h>
      29  #include <stdio_ext.h>
      30  #include <string.h>
      31  
      32  struct nss_database_state
      33  {
      34    struct nss_database_data data;
      35    __libc_lock_define (, lock);
      36    /* If "/" changes, we switched into a container and do NOT want to
      37       reload anything.  This data must be persistent across
      38       reloads.  */
      39    ino64_t root_ino;
      40    dev_t root_dev;
      41  };
      42  
      43  
      44  /* Global NSS database state.  Underlying type is "struct
      45     nss_database_state *" but the allocate_once API requires
      46     "void *".  */
      47  static void *global_database_state;
      48  
      49  /* Allocate and return pointer to nss_database_state object or
      50     on failure return NULL.  */
      51  static void *
      52  global_state_allocate (void *closure)
      53  {
      54    struct nss_database_state *result =  malloc (sizeof (*result));
      55    if (result != NULL)
      56      {
      57        result->data.nsswitch_conf.size = -1; /* Force reload.  */
      58        memset (result->data.services, 0, sizeof (result->data.services));
      59        result->data.initialized = true;
      60        result->data.reload_disabled = false;
      61        __libc_lock_init (result->lock);
      62        result->root_ino = 0;
      63        result->root_dev = 0;
      64      }
      65    return result;
      66  }
      67  
      68  /* Return pointer to global NSS database state, allocating as
      69     required, or returning NULL on failure.  */
      70  static struct nss_database_state *
      71  nss_database_state_get (void)
      72  {
      73    return allocate_once (&global_database_state, global_state_allocate,
      74  			NULL, NULL);
      75  }
      76  
      77  /* Database default selections.  nis/compat mappings get turned into
      78     "files" for !LINK_OBSOLETE_NSL configurations.  */
      79  enum nss_database_default
      80  {
      81   nss_database_default_defconfig = 0, /* "nis [NOTFOUND=return] files".  */
      82   nss_database_default_compat, /* "compat [NOTFOUND=return] files".  */
      83   nss_database_default_dns,    /* "files dns".  */
      84   nss_database_default_files,    /* "files".  */
      85   nss_database_default_nis,    /* "nis".  */
      86   nss_database_default_nis_nisplus,    /* "nis nisplus".  */
      87   nss_database_default_none,      /* Empty list.  */
      88  
      89   NSS_DATABASE_DEFAULT_COUNT     /* Number of defaults.  */
      90  };
      91  
      92  /* Databases not listed default to nss_database_default_defconfig.  */
      93  static const char per_database_defaults[NSS_DATABASE_COUNT] =
      94    {
      95     [nss_database_group] = nss_database_default_compat,
      96     [nss_database_group_compat] = nss_database_default_nis,
      97     [nss_database_gshadow] = nss_database_default_files,
      98     [nss_database_hosts] = nss_database_default_dns,
      99     [nss_database_initgroups] = nss_database_default_none,
     100     [nss_database_networks] = nss_database_default_dns,
     101     [nss_database_passwd] = nss_database_default_compat,
     102     [nss_database_passwd_compat] = nss_database_default_nis,
     103     [nss_database_publickey] = nss_database_default_nis_nisplus,
     104     [nss_database_shadow] = nss_database_default_compat,
     105     [nss_database_shadow_compat] = nss_database_default_nis,
     106    };
     107  
     108  struct nss_database_default_cache
     109  {
     110    nss_action_list caches[NSS_DATABASE_DEFAULT_COUNT];
     111  };
     112  
     113  static bool
     114  nss_database_select_default (struct nss_database_default_cache *cache,
     115                               enum nss_database db, nss_action_list *result)
     116  {
     117    enum nss_database_default def = per_database_defaults[db];
     118    *result = cache->caches[def];
     119    if (*result != NULL)
     120      return true;
     121  
     122    /* Determine the default line string.  */
     123    const char *line;
     124    switch (def)
     125      {
     126  #ifdef LINK_OBSOLETE_NSL
     127      case nss_database_default_defconfig:
     128        line = "nis [NOTFOUND=return] files";
     129        break;
     130      case nss_database_default_compat:
     131        line =  "compat [NOTFOUND=return] files";
     132        break;
     133  #endif
     134  
     135      case nss_database_default_dns:
     136        line = "files dns";
     137        break;
     138  
     139      case nss_database_default_files:
     140  #ifndef LINK_OBSOLETE_NSL
     141      case nss_database_default_defconfig:
     142      case nss_database_default_compat:
     143  #endif
     144        line = "files";
     145        break;
     146  
     147      case nss_database_default_nis:
     148        line = "nis";
     149        break;
     150  
     151      case nss_database_default_nis_nisplus:
     152        line = "nis nisplus";
     153        break;
     154  
     155      case nss_database_default_none:
     156        /* Very special case: Leave *result as NULL.  */
     157        return true;
     158  
     159      case NSS_DATABASE_DEFAULT_COUNT:
     160        __builtin_unreachable ();
     161      }
     162    if (def < 0 || def >= NSS_DATABASE_DEFAULT_COUNT)
     163      /* Tell GCC that line is initialized.  */
     164      __builtin_unreachable ();
     165  
     166    *result = __nss_action_parse (line);
     167    if (*result == NULL)
     168      {
     169        assert (errno == ENOMEM);
     170        return false;
     171      }
     172    return true;
     173  }
     174  
     175  /* database_name must be large enough for each individual name plus a
     176     null terminator.  */
     177  typedef char database_name[14];
     178  #define DEFINE_DATABASE(name) \
     179    _Static_assert (sizeof (#name) <= sizeof (database_name), #name);
     180  #include "databases.def"
     181  #undef DEFINE_DATABASE
     182  
     183  static const database_name nss_database_name_array[] =
     184    {
     185  #define DEFINE_DATABASE(name) #name,
     186  #include "databases.def"
     187  #undef DEFINE_DATABASE
     188    };
     189  
     190  static int
     191  name_search (const void *left, const void *right)
     192  {
     193    return strcmp (left, right);
     194  }
     195  
     196  static int
     197  name_to_database_index (const char *name)
     198  {
     199    database_name *name_entry = bsearch (name, nss_database_name_array,
     200                                         array_length (nss_database_name_array),
     201                                         sizeof (database_name), name_search);
     202    if (name_entry == NULL)
     203      return -1;
     204    return name_entry - nss_database_name_array;
     205  }
     206  
     207  static bool
     208  process_line (struct nss_database_data *data, char *line)
     209  {
     210    /* Ignore leading white spaces.  ATTENTION: this is different from
     211       what is implemented in Solaris.  The Solaris man page says a line
     212       beginning with a white space character is ignored.  We regard
     213       this as just another misfeature in Solaris.  */
     214    while (isspace (line[0]))
     215      ++line;
     216  
     217    /* Recognize `<database> ":"'.  */
     218    char *name = line;
     219    while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
     220      ++line;
     221    if (line[0] == '\0' || name == line)
     222      /* Syntax error.  Skip this line.  */
     223      return true;
     224    while (line[0] != '\0' && (isspace (line[0]) || line[0] == ':'))
     225      *line++ = '\0';
     226  
     227    int db = name_to_database_index (name);
     228    if (db < 0)
     229      /* Not our database e.g. sudoers, automount, etc.  */
     230      return true;
     231  
     232    nss_action_list result = __nss_action_parse (line);
     233    if (result == NULL)
     234      return false;
     235    data->services[db] = result;
     236    return true;
     237  }
     238  
     239  int
     240  __nss_configure_lookup (const char *dbname, const char *service_line)
     241  {
     242    int db;
     243    nss_action_list result;
     244    struct nss_database_state *local;
     245  
     246    /* Convert named database to index.  */
     247    db = name_to_database_index (dbname);
     248    if (db < 0)
     249      /* Not our database (e.g., sudoers).  */
     250      return -1;
     251  
     252    /* Force any load/cache/read whatever to happen, so we can override
     253       it.  */
     254    __nss_database_get (db, &result);
     255  
     256    local = nss_database_state_get ();
     257  
     258    result = __nss_action_parse (service_line);
     259    if (result == NULL)
     260      return -1;
     261  
     262    atomic_store_release (&local->data.reload_disabled, 1);
     263    local->data.services[db] = result;
     264  
     265  #ifdef USE_NSCD
     266    __nss_database_custom[db] = true;
     267  #endif
     268  
     269    return 0;
     270  }
     271  
     272  /* Iterate over the lines in FP, parse them, and store them in DATA.
     273     Return false on memory allocation failure, true on success.  */
     274  static bool
     275  nss_database_reload_1 (struct nss_database_data *data, FILE *fp)
     276  {
     277    char *line = NULL;
     278    size_t line_allocated = 0;
     279    bool result = false;
     280  
     281    while (true)
     282      {
     283        ssize_t ret = __getline (&line, &line_allocated, fp);
     284        if (__ferror_unlocked (fp))
     285          break;
     286        if (__feof_unlocked (fp))
     287          {
     288            result = true;
     289            break;
     290          }
     291        assert (ret > 0);
     292        (void) ret;               /* For NDEBUG builds.  */
     293  
     294        if (!process_line (data, line))
     295          break;
     296      }
     297  
     298    free (line);
     299    return result;
     300  }
     301  
     302  static bool
     303  nss_database_reload (struct nss_database_data *staging,
     304                       struct file_change_detection *initial)
     305  {
     306    FILE *fp = fopen (_PATH_NSSWITCH_CONF, "rce");
     307    if (fp == NULL)
     308      switch (errno)
     309        {
     310        case EACCES:
     311        case EISDIR:
     312        case ELOOP:
     313        case ENOENT:
     314        case ENOTDIR:
     315        case EPERM:
     316          /* Ignore these errors.  They are persistent errors caused
     317             by file system contents.  */
     318          break;
     319        default:
     320          /* Other errors refer to resource allocation problems and
     321             need to be handled by the application.  */
     322          return false;
     323        }
     324    else
     325      /* No other threads have access to fp.  */
     326      __fsetlocking (fp, FSETLOCKING_BYCALLER);
     327  
     328    /* We start with all of *staging pointing to NULL.  */
     329  
     330    bool ok = true;
     331    if (fp != NULL)
     332      ok = nss_database_reload_1 (staging, fp);
     333  
     334    /* Now we have non-NULL entries where the user explicitly listed the
     335       service in nsswitch.conf.  */
     336  
     337    /* Apply defaults.  */
     338    if (ok)
     339      {
     340        struct nss_database_default_cache cache = { };
     341  
     342        /* These three default to other services if the user listed the
     343  	 other service.  */
     344  
     345        /* "shadow_compat" defaults to "passwd_compat" if only the
     346  	 latter is given.  */
     347        if (staging->services[nss_database_shadow_compat] == NULL)
     348  	staging->services[nss_database_shadow_compat] =
     349  	  staging->services[nss_database_passwd_compat];
     350  
     351        /* "shadow" defaults to "passwd" if only the latter is
     352  	 given.  */
     353        if (staging->services[nss_database_shadow] == NULL)
     354  	staging->services[nss_database_shadow] =
     355  	  staging->services[nss_database_passwd];
     356  
     357        /* "gshadow" defaults to "group" if only the latter is
     358  	 given.  */
     359        if (staging->services[nss_database_gshadow] == NULL)
     360  	staging->services[nss_database_gshadow] =
     361  	  staging->services[nss_database_group];
     362  
     363        /* For anything still unspecified, load the default configs.  */
     364  
     365        for (int i = 0; i < NSS_DATABASE_COUNT; ++i)
     366          if (staging->services[i] == NULL)
     367            {
     368              ok = nss_database_select_default (&cache, i,
     369                                                &staging->services[i]);
     370              if (!ok)
     371                break;
     372            }
     373      }
     374  
     375    if (ok)
     376      ok = __file_change_detection_for_fp (&staging->nsswitch_conf, fp);
     377  
     378    if (fp != NULL)
     379      {
     380        int saved_errno = errno;
     381        fclose (fp);
     382        __set_errno (saved_errno);
     383      }
     384  
     385    if (ok && !__file_is_unchanged (&staging->nsswitch_conf, initial))
     386      /* Reload is required because the file changed while reading.  */
     387      staging->nsswitch_conf.size = -1;
     388  
     389    return ok;
     390  }
     391  
     392  static bool
     393  nss_database_check_reload_and_get (struct nss_database_state *local,
     394                                     nss_action_list *result,
     395                                     enum nss_database database_index)
     396  {
     397    struct __stat64_t64 str;
     398  
     399    /* Acquire MO is needed because the thread that sets reload_disabled
     400       may have loaded the configuration first, so synchronize with the
     401       Release MO store there.  */
     402    if (atomic_load_acquire (&local->data.reload_disabled))
     403      {
     404        *result = local->data.services[database_index];
     405        /* No reload, so there is no error.  */
     406        return true;
     407      }
     408  
     409    struct file_change_detection initial;
     410    if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF))
     411      return false;
     412  
     413    __libc_lock_lock (local->lock);
     414    if (__file_is_unchanged (&initial, &local->data.nsswitch_conf))
     415      {
     416        /* Configuration is up-to-date.  Read it and return it to the
     417           caller.  */
     418        *result = local->data.services[database_index];
     419        __libc_lock_unlock (local->lock);
     420        return true;
     421      }
     422  
     423    int stat_rv = __stat64_time64 ("/", &str);
     424  
     425    if (local->data.services[database_index] != NULL)
     426      {
     427        /* Before we reload, verify that "/" hasn't changed.  We assume that
     428          errors here are very unlikely, but the chance that we're entering
     429          a container is also very unlikely, so we err on the side of both
     430          very unlikely things not happening at the same time.  */
     431        if (stat_rv != 0
     432  	  || (local->root_ino != 0
     433  	      && (str.st_ino != local->root_ino
     434  		  ||  str.st_dev != local->root_dev)))
     435  	{
     436          /* Change detected; disable reloading and return current state.  */
     437          atomic_store_release (&local->data.reload_disabled, 1);
     438          *result = local->data.services[database_index];
     439          __libc_lock_unlock (local->lock);
     440          return true;
     441        }
     442      }
     443    if (stat_rv == 0)
     444      {
     445        local->root_ino = str.st_ino;
     446        local->root_dev = str.st_dev;
     447      }
     448  
     449    __libc_lock_unlock (local->lock);
     450  
     451    /* Avoid overwriting the global configuration until we have loaded
     452       everything successfully.  Otherwise, if the file change
     453       information changes back to what is in the global configuration,
     454       the lookups would use the partially-written  configuration.  */
     455    struct nss_database_data staging = { .initialized = true, };
     456  
     457    bool ok = nss_database_reload (&staging, &initial);
     458  
     459    if (ok)
     460      {
     461        __libc_lock_lock (local->lock);
     462  
     463        /* See above for memory order.  */
     464        if (!atomic_load_acquire (&local->data.reload_disabled))
     465          /* This may go back in time if another thread beats this
     466             thread with the update, but in this case, a reload happens
     467             on the next NSS call.  */
     468          local->data = staging;
     469  
     470        *result = local->data.services[database_index];
     471        __libc_lock_unlock (local->lock);
     472      }
     473  
     474    return ok;
     475  }
     476  
     477  bool
     478  __nss_database_get (enum nss_database db, nss_action_list *actions)
     479  {
     480    struct nss_database_state *local = nss_database_state_get ();
     481    return nss_database_check_reload_and_get (local, actions, db);
     482  }
     483  libc_hidden_def (__nss_database_get)
     484  
     485  nss_action_list
     486  __nss_database_get_noreload (enum nss_database db)
     487  {
     488    /* There must have been a previous __nss_database_get call.  */
     489    struct nss_database_state *local = atomic_load_acquire (&global_database_state);
     490    assert (local != NULL);
     491  
     492    __libc_lock_lock (local->lock);
     493    nss_action_list result = local->data.services[db];
     494    __libc_lock_unlock (local->lock);
     495    return result;
     496  }
     497  
     498  void
     499  __nss_database_freeres (void)
     500  {
     501    free (global_database_state);
     502    global_database_state = NULL;
     503  }
     504  
     505  void
     506  __nss_database_fork_prepare_parent (struct nss_database_data *data)
     507  {
     508    /* Do not use allocate_once to trigger loading unnecessarily.  */
     509    struct nss_database_state *local = atomic_load_acquire (&global_database_state);
     510    if (local == NULL)
     511      data->initialized = false;
     512    else
     513      {
     514        /* Make a copy of the configuration.  This approach was chosen
     515           because it avoids acquiring the lock during the actual
     516           fork.  */
     517        __libc_lock_lock (local->lock);
     518        *data = local->data;
     519        __libc_lock_unlock (local->lock);
     520      }
     521  }
     522  
     523  void
     524  __nss_database_fork_subprocess (struct nss_database_data *data)
     525  {
     526    struct nss_database_state *local = atomic_load_acquire (&global_database_state);
     527    if (data->initialized)
     528      {
     529        /* Restore the state at the point of the fork.  */
     530        assert (local != NULL);
     531        local->data = *data;
     532        __libc_lock_init (local->lock);
     533      }
     534    else if (local != NULL)
     535      /* The NSS configuration was loaded concurrently during fork.  We
     536         do not know its state, so we need to discard it.  */
     537      global_database_state = NULL;
     538  }