Back to index

glibc  2.9
Defines | Functions | Variables
nsswitch.c File Reference
#include <ctype.h>
#include <dlfcn.h>
#include <errno.h>
#include <netdb.h>
#include <bits/libc-lock.h>
#include <search.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <aliases.h>
#include <grp.h>
#include <netinet/ether.h>
#include <pwd.h>
#include <shadow.h>
#include <gnu/lib-names.h>
#include "nsswitch.h"
#include "../nscd/nscd_proto.h"
#include "databases.def"

Go to the source code of this file.

Defines

#define DEFINE_DATABASE(name)
#define DEFINE_DATABASE(name)   { #name, &__nss_##name##_database },
#define ndatabases   (sizeof (databases) / sizeof (databases[0]))

Functions

static name_databasenss_parse_file (const char *fname) internal_function
static name_database_entrynss_getline (char *line) internal_function
static service_usernss_parse_service_list (const char *line) internal_function
static service_librarynss_new_service (name_database *database, const char *name) internal_function
 __libc_lock_define_initialized (static, lock)
 libc_hidden_def (__nss_database_lookup)
int __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, void **fctp, int status, int all_values)
 libc_hidden_def (__nss_next2)
int __nss_configure_lookup (const char *dbname, const char *service_line)
static int known_compare (const void *p1, const void *p2)
void * __nss_lookup_function (service_user *ni, const char *fct_name)
 libc_hidden_def (__nss_lookup_function)
void __nss_disable_nscd (void)
 libc_freeres_fn (free_mem)

Variables

struct {
const char name [10]
service_user ** dbp
databases []

Define Documentation

#define DEFINE_DATABASE (   name)
Value:
extern service_user *__nss_##name##_database attribute_hidden;       \
  weak_extern (__nss_##name##_database)

Definition at line 54 of file nsswitch.c.

#define DEFINE_DATABASE (   name)    { #name, &__nss_##name##_database },

Definition at line 54 of file nsswitch.c.

#define ndatabases   (sizeof (databases) / sizeof (databases[0]))

Definition at line 72 of file nsswitch.c.


Function Documentation

__libc_lock_define_initialized ( static  ,
lock   
)

Definition at line 75 of file nsswitch.c.

{
  /* Prevent multiple threads to change the service table.  */
  __libc_lock_lock (lock);

  /* Reconsider database variable in case some other thread called
     `__nss_configure_lookup' while we waited for the lock.  */
  if (*ni != NULL)
    {
      __libc_lock_unlock (lock);
      return 0;
    }

  /* Are we initialized yet?  */
  if (service_table == NULL)
    /* Read config file.  */
    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);

  /* Test whether configuration data is available.  */
  if (service_table != NULL)
    {
      /* Return first `service_user' entry for DATABASE.  */
      name_database_entry *entry;

      /* XXX Could use some faster mechanism here.  But each database is
        only requested once and so this might not be critical.  */
      for (entry = service_table->entry; entry != NULL; entry = entry->next)
       if (strcmp (database, entry->name) == 0)
         *ni = entry->service;

      if (*ni == NULL && alternate_name != NULL)
       /* We haven't found an entry so far.  Try to find it with the
          alternative name.  */
       for (entry = service_table->entry; entry != NULL; entry = entry->next)
         if (strcmp (alternate_name, entry->name) == 0)
           *ni = entry->service;
    }

  /* No configuration data is available, either because nsswitch.conf
     doesn't exist or because it doesn't has a line for this database.

     DEFCONFIG specifies the default service list for this database,
     or null to use the most common default.  */
  if (*ni == NULL)
    *ni = nss_parse_service_list (defconfig
                              ?: "nis [NOTFOUND=return] files");

  __libc_lock_unlock (lock);

  return 0;
}

Here is the call graph for this function:

int __nss_configure_lookup ( const char *  dbname,
const char *  service_line 
)

Definition at line 226 of file nsswitch.c.

{
  service_user *new_db;
  size_t cnt;

  for (cnt = 0; cnt < ndatabases; ++cnt)
    {
      int cmp = strcmp (dbname, databases[cnt].name);
      if (cmp == 0)
       break;
      if (cmp < 0)
       {
         __set_errno (EINVAL);
         return -1;
       }
    }

  if (cnt == ndatabases)
    {
      __set_errno (EINVAL);
      return -1;
    }

  /* Test whether it is really used.  */
  if (databases[cnt].dbp == NULL)
    /* Nothing to do, but we could do.  */
    return 0;

  /* Try to generate new data.  */
  new_db = nss_parse_service_list (service_line);
  if (new_db == NULL)
    {
      /* Illegal service specification.  */
      __set_errno (EINVAL);
      return -1;
    }

  /* Prevent multiple threads to change the service table.  */
  __libc_lock_lock (lock);

  /* Install new rules.  */
  *databases[cnt].dbp = new_db;

  __libc_lock_unlock (lock);

  return 0;
}

Here is the call graph for this function:

void __nss_disable_nscd ( void  )

Definition at line 721 of file nsswitch.c.

Here is the caller graph for this function:

void* __nss_lookup_function ( service_user ni,
const char *  fct_name 
)

Definition at line 285 of file nsswitch.c.

{
  void **found, *result;

  /* We now modify global data.  Protect it.  */
  __libc_lock_lock (lock);

  /* Search the tree of functions previously requested.  Data in the
     tree are `known_function' structures, whose first member is a
     `const char *', the lookup key.  The search returns a pointer to
     the tree node structure; the first member of the is a pointer to
     our structure (i.e. what will be a `known_function'); since the
     first member of that is the lookup key string, &FCT_NAME is close
     enough to a pointer to our structure to use as a lookup key that
     will be passed to `known_compare' (above).  */

  found = __tsearch (&fct_name, &ni->known, &known_compare);
  if (*found != &fct_name)
    /* The search found an existing structure in the tree.  */
    result = ((known_function *) *found)->fct_ptr;
  else
    {
      /* This name was not known before.  Now we have a node in the tree
        (in the proper sorted position for FCT_NAME) that points to
        &FCT_NAME instead of any real `known_function' structure.
        Allocate a new structure and fill it in.  */

      known_function *known = malloc (sizeof *known);
      if (! known)
       {
       remove_from_tree:
         /* Oops.  We can't instantiate this node properly.
            Remove it from the tree.  */
         __tdelete (&fct_name, &ni->known, &known_compare);
         result = NULL;
       }
      else
       {
         /* Point the tree node at this new structure.  */
         *found = known;
         known->fct_name = fct_name;

         if (ni->library == NULL)
           {
             /* This service has not yet been used.  Fetch the service
               library for it, creating a new one if need be.  If there
               is no service table from the file, this static variable
               holds the head of the service_library list made from the
               default configuration.  */
             static name_database default_table;
             ni->library = nss_new_service (service_table ?: &default_table,
                                        ni->name);
             if (ni->library == NULL)
              {
                /* This only happens when out of memory.  */
                free (known);
                goto remove_from_tree;
              }
           }

#if !defined DO_STATIC_NSS || defined SHARED
         if (ni->library->lib_handle == NULL)
           {
             /* Load the shared library.  */
             size_t shlen = (7 + strlen (ni->library->name) + 3
                           + strlen (__nss_shlib_revision) + 1);
             int saved_errno = errno;
             char shlib_name[shlen];

             /* Construct shared object name.  */
             __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
                                                "libnss_"),
                                       ni->library->name),
                              ".so"),
                     __nss_shlib_revision);

             ni->library->lib_handle = __libc_dlopen (shlib_name);
             if (ni->library->lib_handle == NULL)
              {
                /* Failed to load the library.  */
                ni->library->lib_handle = (void *) -1l;
                __set_errno (saved_errno);
              }
           }

         if (ni->library->lib_handle == (void *) -1l)
           /* Library not found => function not found.  */
           result = NULL;
         else
           {
             /* Get the desired function.  */
             size_t namlen = (5 + strlen (ni->library->name) + 1
                            + strlen (fct_name) + 1);
             char name[namlen];

             /* Construct the function name.  */
             __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
                                       ni->library->name),
                              "_"),
                     fct_name);

             /* Look up the symbol.  */
             result = __libc_dlsym (ni->library->lib_handle, name);
           }
#else
         /* We can't get function address dynamically in static linking. */
         {
# define DEFINE_ENT(h,nm)                                            \
           { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },               \
           { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },                   \
           { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
# define DEFINE_GET(h,nm)                                            \
           { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
# define DEFINE_GETBY(h,nm,ky)                                              \
           { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
           static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
             {
# include "function.def"
              { NULL, NULL }
             };
           size_t namlen = (5 + strlen (ni->library->name) + 1
                          + strlen (fct_name) + 1);
           char name[namlen];

           /* Construct the function name.  */
           __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
                            "_"),
                    fct_name);

           result = NULL;
           for (tp = &tbl[0]; tp->fname; tp++)
             if (strcmp (tp->fname, name) == 0)
              {
                result = tp->fp;
                break;
              }
         }
#endif

         /* Remember function pointer for later calls.  Even if null, we
            record it so a second try needn't search the library again.  */
         known->fct_ptr = result;
       }
    }

  /* Remove the lock.  */
  __libc_lock_unlock (lock);

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int __nss_next2 ( service_user **  ni,
const char *  fct_name,
const char *  fct2_name,
void **  fctp,
int  status,
int  all_values 
)

Definition at line 174 of file nsswitch.c.

{
  if (all_values)
    {
      if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
         && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
         && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
         && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
       return 1;
    }
  else
    {
      /* This is really only for debugging.  */
      if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
                         || status > NSS_STATUS_RETURN, 0))
        __libc_fatal ("illegal status in __nss_next");

       if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
        return 1;
    }

  if ((*ni)->next == NULL)
    return -1;

  do
    {
      *ni = (*ni)->next;

      *fctp = __nss_lookup_function (*ni, fct_name);
      if (*fctp == NULL && fct2_name != NULL)
       *fctp = __nss_lookup_function (*ni, fct2_name);
    }
  while (*fctp == NULL
        && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
        && (*ni)->next != NULL);

  return *fctp != NULL ? 0 : -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int known_compare ( const void *  p1,
const void *  p2 
) [static]

Definition at line 277 of file nsswitch.c.

{
  return p1 == p2 ? 0 : strcmp (*(const char *const *) p1,
                            *(const char *const *) p2);
}

Here is the caller graph for this function:

libc_freeres_fn ( free_mem  )

Definition at line 732 of file nsswitch.c.

{
  name_database *top = service_table;
  name_database_entry *entry;
  service_library *library;

  if (top == NULL)
    /* Maybe we have not read the nsswitch.conf file.  */
    return;

  /* Don't disturb ongoing other threads (if there are any).  */
  service_table = NULL;

  entry = top->entry;
  while (entry != NULL)
    {
      name_database_entry *olde = entry;
      service_user *service = entry->service;

      while (service != NULL)
       {
         service_user *olds = service;

         if (service->known != NULL)
           __tdestroy (service->known, free);

         service = service->next;
         free (olds);
       }

      entry = entry->next;
      free (olde);
    }

  library = top->library;
  while (library != NULL)
    {
      service_library *oldl = library;

      if (library->lib_handle && library->lib_handle != (void *) -1l)
       __libc_dlclose (library->lib_handle);

      library = library->next;
      free (oldl);
    }

  free (top);
}

Here is the call graph for this function:

Definition at line 141 of file nsswitch.c.

{
  *fctp = __nss_lookup_function (*ni, fct_name);
  if (*fctp == NULL && fct2_name != NULL)
    *fctp = __nss_lookup_function (*ni, fct2_name);

  while (*fctp == NULL
        && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
        && (*ni)->next != NULL)
    {
      *ni = (*ni)->next;

      *fctp = __nss_lookup_function (*ni, fct_name);
      if (*fctp == NULL && fct2_name != NULL)
       *fctp = __nss_lookup_function (*ni, fct2_name);
    }

  return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
}

Here is the call graph for this function:

Definition at line 213 of file nsswitch.c.

Here is the call graph for this function:

Definition at line 435 of file nsswitch.c.

{
  FILE *fp;
  name_database *result;
  name_database_entry *last;
  char *line;
  size_t len;

  /* Open the configuration file.  */
  fp = fopen (fname, "rc");
  if (fp == NULL)
    return NULL;

  /* No threads use this stream.  */
  __fsetlocking (fp, FSETLOCKING_BYCALLER);

  result = (name_database *) malloc (sizeof (name_database));
  if (result == NULL)
    return NULL;

  result->entry = NULL;
  result->library = NULL;
  last = NULL;
  line = NULL;
  len = 0;
  do
    {
      name_database_entry *this;
      ssize_t n;

      n = __getline (&line, &len, fp);
      if (n < 0)
       break;
      if (line[n - 1] == '\n')
       line[n - 1] = '\0';

      /* Because the file format does not know any form of quoting we
        can search forward for the next '#' character and if found
        make it terminating the line.  */
      *__strchrnul (line, '#') = '\0';

      /* If the line is blank it is ignored.  */
      if (line[0] == '\0')
       continue;

      /* Each line completely specifies the actions for a database.  */
      this = nss_getline (line);
      if (this != NULL)
       {
         if (last != NULL)
           last->next = this;
         else
           result->entry = this;

         last = this;
       }
    }
  while (!feof_unlocked (fp));

  /* Free the buffer.  */
  free (line);
  /* Close configuration file.  */
  fclose (fp);

  return result;
}

Here is the call graph for this function:

static name_database_entry *internal_function nss_getline ( char *  line) [static]

Definition at line 654 of file nsswitch.c.

{
  const char *name;
  name_database_entry *result;
  size_t len;

  /* 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> ":"'.  */
  name = line;
  while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
    ++line;
  if (line[0] == '\0' || name == line)
    /* Syntax error.  */
    return NULL;
  *line++ = '\0';

  len = strlen (name) + 1;

  result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
  if (result == NULL)
    return NULL;

  /* Save the database name.  */
  memcpy (result->name, name, len);

  /* Parse the list of services.  */
  result->service = nss_parse_service_list (line);

  result->next = NULL;
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static service_library *internal_function nss_new_service ( name_database database,
const char *  name 
) [static]

Definition at line 695 of file nsswitch.c.

{
  service_library **currentp = &database->library;

  while (*currentp != NULL)
    {
      if (strcmp ((*currentp)->name, name) == 0)
       return *currentp;
      currentp = &(*currentp)->next;
    }

  /* We have to add the new service.  */
  *currentp = (service_library *) malloc (sizeof (service_library));
  if (*currentp == NULL)
    return NULL;

  (*currentp)->name = name;
  (*currentp)->lib_handle = NULL;
  (*currentp)->next = NULL;

  return *currentp;
}

Here is the caller graph for this function:

static name_database* nss_parse_file ( const char *  fname) [static]

Here is the caller graph for this function:

static service_user *internal_function nss_parse_service_list ( const char *  line) [static]

Definition at line 513 of file nsswitch.c.

{
  service_user *result = NULL, **nextp = &result;

  while (1)
    {
      service_user *new_service;
      const char *name;

      while (isspace (line[0]))
       ++line;
      if (line[0] == '\0')
       /* No source specified.  */
       return result;

      /* Read <source> identifier.  */
      name = line;
      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
       ++line;
      if (name == line)
       return result;


      new_service = (service_user *) malloc (sizeof (service_user)
                                        + (line - name + 1));
      if (new_service == NULL)
       return result;

      *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';

      /* Set default actions.  */
      new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
      new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
      new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
      new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
      new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
      new_service->library = NULL;
      new_service->known = NULL;
      new_service->next = NULL;

      while (isspace (line[0]))
       ++line;

      if (line[0] == '[')
       {
         /* Read criterions.  */
         do
           ++line;
         while (line[0] != '\0' && isspace (line[0]));

         do
           {
             int not;
             enum nss_status status;
             lookup_actions action;

             /* Grok ! before name to mean all statii but that one.  */
             not = line[0] == '!';
             if (not)
              ++line;

             /* Read status name.  */
             name = line;
             while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
                   && line[0] != ']')
              ++line;

             /* Compare with known statii.  */
             if (line - name == 7)
              {
                if (__strncasecmp (name, "SUCCESS", 7) == 0)
                  status = NSS_STATUS_SUCCESS;
                else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
                  status = NSS_STATUS_UNAVAIL;
                else
                  return result;
              }
             else if (line - name == 8)
              {
                if (__strncasecmp (name, "NOTFOUND", 8) == 0)
                  status = NSS_STATUS_NOTFOUND;
                else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
                  status = NSS_STATUS_TRYAGAIN;
                else
                  return result;
              }
             else
              return result;

             while (isspace (line[0]))
              ++line;
             if (line[0] != '=')
              return result;
             do
              ++line;
             while (isspace (line[0]));

             name = line;
             while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
                   && line[0] != ']')
              ++line;

             if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
              action = NSS_ACTION_RETURN;
             else if (line - name == 8
                     && __strncasecmp (name, "CONTINUE", 8) == 0)
              action = NSS_ACTION_CONTINUE;
             else
              return result;

             if (not)
              {
                /* Save the current action setting for this status,
                   set them all to the given action, and reset this one.  */
                const lookup_actions save = new_service->actions[2 + status];
                new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
                new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
                new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
                new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
                new_service->actions[2 + status] = save;
              }
             else
              new_service->actions[2 + status] = action;

             /* Skip white spaces.  */
             while (isspace (line[0]))
              ++line;
           }
         while (line[0] != ']');

         /* Skip the ']'.  */
         ++line;
       }

      *nextp = new_service;
      nextp = &new_service->next;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

struct { ... } databases[] [static]