(linenum→info "unix/slp.c:2238")

glibc/2.7/nss/nsswitch.c

    1: /* Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
    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, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <ctype.h>
   21: #include <dlfcn.h>
   22: #include <errno.h>
   23: #include <netdb.h>
   24: #include <bits/libc-lock.h>
   25: #include <search.h>
   26: #include <stdio.h>
   27: #include <stdio_ext.h>
   28: #include <stdlib.h>
   29: #include <string.h>
   30: 
   31: #include <aliases.h>
   32: #include <grp.h>
   33: #include <netinet/ether.h>
   34: #include <pwd.h>
   35: #include <shadow.h>
   36: 
   37: #if !defined DO_STATIC_NSS || defined SHARED
   38: # include <gnu/lib-names.h>
   39: #endif
   40: 
   41: #include "nsswitch.h"
   42: #include "../nscd/nscd_proto.h"
   43: 
   44: /* Prototypes for the local functions.  */
   45: static name_database *nss_parse_file (const char *fname) internal_function;
   46: static name_database_entry *nss_getline (char *line) internal_function;
   47: static service_user *nss_parse_service_list (const char *line)
   48:      internal_function;
   49: static service_library *nss_new_service (name_database *database,
   50:                                          const char *name) internal_function;
   51: 
   52: 
   53: /* Declare external database variables.  */
   54: #define DEFINE_DATABASE(name)                                                 \
   55:   extern service_user *__nss_##name##_database attribute_hidden;              \
   56:   weak_extern (__nss_##name##_database)
   57: #include "databases.def"
   58: #undef DEFINE_DATABASE
   59: 
   60: /* Structure to map database name to variable.  */
   61: static const struct
   62: {
   63:   const char name[10];
   64:   service_user **dbp;
   65: } databases[] =
   66: {
   67: #define DEFINE_DATABASE(name)                                                 \
   68:   { #name, &__nss_##name##_database },
   69: #include "databases.def"
   70: #undef DEFINE_DATABASE
   71: };
   72: #define ndatabases (sizeof (databases) / sizeof (databases[0]))
   73: 
   74: 
   75: __libc_lock_define_initialized (static, lock)
   76: 
   77: #if !defined DO_STATIC_NSS || defined SHARED
   78: /* String with revision number of the shared object files.  */
   79: static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
   80: #endif
   81: 
   82: /* The root of the whole data base.  */
   83: static name_database *service_table;
   84: 
   85: 
   86: /* -1 == database not found
   87:     0 == database entry pointer stored */
   88: int
   89: __nss_database_lookup (const char *database, const char *alternate_name,
   90:                        const char *defconfig, service_user **ni)
   91: {
   92:   /* Prevent multiple threads to change the service table.  */
   93:   __libc_lock_lock (lock);
   94: 
   95:   /* Reconsider database variable in case some other thread called
   96:      `__nss_configure_lookup' while we waited for the lock.  */
   97:   if (*ni != NULL)
   98:     {
   99:       __libc_lock_unlock (lock);
  100:       return 0;
  101:     }
  102: 
  103:   /* Are we initialized yet?  */
  104:   if (service_table == NULL)
  105:     /* Read config file.  */
  106:     service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
  107: 
  108:   /* Test whether configuration data is available.  */
  109:   if (service_table != NULL)
  110:     {
  111:       /* Return first `service_user' entry for DATABASE.  */
  112:       name_database_entry *entry;
  113: 
  114:       /* XXX Could use some faster mechanism here.  But each database is
  115:          only requested once and so this might not be critical.  */
  116:       for (entry = service_table->entry; entry != NULL; entry = entry->next)
  117:         if (strcmp (database, entry->name) == 0)
  118:           *ni = entry->service;
  119: 
  120:       if (*ni == NULL && alternate_name != NULL)
  121:         /* We haven't found an entry so far.  Try to find it with the
  122:            alternative name.  */
  123:         for (entry = service_table->entry; entry != NULL; entry = entry->next)
  124:           if (strcmp (alternate_name, entry->name) == 0)
  125:             *ni = entry->service;
  126:     }
  127: 
  128:   /* No configuration data is available, either because nsswitch.conf
  129:      doesn't exist or because it doesn't has a line for this database.
  130: 
  131:      DEFCONFIG specifies the default service list for this database,
  132:      or null to use the most common default.  */
  133:   if (*ni == NULL)
  134:     *ni = nss_parse_service_list (defconfig
  135:                                   ?: "nis [NOTFOUND=return] files");
  136: 
  137:   __libc_lock_unlock (lock);
  138: 
  139:   return 0;
  140: }
  141: libc_hidden_def (__nss_database_lookup)
  142: 
  143: 
  144: /* -1 == not found
  145:     0 == function found
  146:     1 == finished */
  147: int
  148: __nss_lookup (service_user **ni, const char *fct_name, void **fctp)
  149: {
  150:   *fctp = __nss_lookup_function (*ni, fct_name);
  151: 
  152:   while (*fctp == NULL
  153:          && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
  154:          && (*ni)->next != NULL)
  155:     {
  156:       *ni = (*ni)->next;
  157: 
  158:       *fctp = __nss_lookup_function (*ni, fct_name);
  159:     }
  160: 
  161:   return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
  162: }
  163: 
  164: 
  165: /* -1 == not found
  166:     0 == adjusted for next function
  167:     1 == finished */
  168: int
  169: __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
  170:             int all_values)
  171: {
  172:   if (all_values)
  173:     {
  174:       if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
  175:           && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
  176:           && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
  177:           && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
  178:         return 1;
  179:     }
  180:   else
  181:     {
  182:       /* This is really only for debugging.  */
  183:        if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
  184:          __libc_fatal ("illegal status in __nss_next");
  185: 
  186:        if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
  187:          return 1;
  188:     }
  189: 
  190:   if ((*ni)->next == NULL)
  191:     return -1;
  192: 
  193:   do
  194:     {
  195:       *ni = (*ni)->next;
  196: 
  197:       *fctp = __nss_lookup_function (*ni, fct_name);
  198:     }
  199:   while (*fctp == NULL
  200:          && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
  201:          && (*ni)->next != NULL);
  202: 
  203:   return *fctp != NULL ? 0 : -1;
  204: }
  205: libc_hidden_def (__nss_next)
  206: 
  207: 
  208: int
  209: __nss_configure_lookup (const char *dbname, const char *service_line)
  210: {
  211:   service_user *new_db;
  212:   size_t cnt;
  213: 
  214:   for (cnt = 0; cnt < ndatabases; ++cnt)
  215:     {
  216:       int cmp = strcmp (dbname, databases[cnt].name);
  217:       if (cmp == 0)
  218:         break;
  219:       if (cmp < 0)
  220:         {
  221:           __set_errno (EINVAL);
  222:           return -1;
  223:         }
  224:     }
  225: 
  226:   if (cnt == ndatabases)
  227:     {
  228:       __set_errno (EINVAL);
  229:       return -1;
  230:     }
  231: 
  232:   /* Test whether it is really used.  */
  233:   if (databases[cnt].dbp == NULL)
  234:     /* Nothing to do, but we could do.  */
  235:     return 0;
  236: 
  237:   /* Try to generate new data.  */
  238:   new_db = nss_parse_service_list (service_line);
  239:   if (new_db == NULL)
  240:     {
  241:       /* Illegal service specification.  */
  242:       __set_errno (EINVAL);
  243:       return -1;
  244:     }
  245: 
  246:   /* Prevent multiple threads to change the service table.  */
  247:   __libc_lock_lock (lock);
  248: 
  249:   /* Install new rules.  */
  250:   *databases[cnt].dbp = new_db;
  251: 
  252:   __libc_lock_unlock (lock);
  253: 
  254:   return 0;
  255: }
  256: 
  257: 
  258: /* Comparison function for searching NI->known tree.  */
  259: static int
  260: known_compare (const void *p1, const void *p2)
  261: {
  262:   return p1 == p2 ? 0 : strcmp (*(const char *const *) p1,
  263:                                 *(const char *const *) p2);
  264: }
  265: 
  266: 
  267: void *
  268: __nss_lookup_function (service_user *ni, const char *fct_name)
  269: {
  270:   void **found, *result;
  271: 
  272:   /* We now modify global data.  Protect it.  */
  273:   __libc_lock_lock (lock);
  274: 
  275:   /* Search the tree of functions previously requested.  Data in the
  276:      tree are `known_function' structures, whose first member is a
  277:      `const char *', the lookup key.  The search returns a pointer to
  278:      the tree node structure; the first member of the is a pointer to
  279:      our structure (i.e. what will be a `known_function'); since the
  280:      first member of that is the lookup key string, &FCT_NAME is close
  281:      enough to a pointer to our structure to use as a lookup key that
  282:      will be passed to `known_compare' (above).  */
  283: 
  284:   found = __tsearch (&fct_name, &ni->known, &known_compare);
  285:   if (*found != &fct_name)
  286:     /* The search found an existing structure in the tree.  */
  287:     result = ((known_function *) *found)->fct_ptr;
  288:   else
  289:     {
  290:       /* This name was not known before.  Now we have a node in the tree
  291:          (in the proper sorted position for FCT_NAME) that points to
  292:          &FCT_NAME instead of any real `known_function' structure.
  293:          Allocate a new structure and fill it in.  */
  294: 
  295:       known_function *known = malloc (sizeof *known);
  296:       if (! known)
  297:         {
  298:         remove_from_tree:
  299:           /* Oops.  We can't instantiate this node properly.
  300:              Remove it from the tree.  */
  301:           __tdelete (&fct_name, &ni->known, &known_compare);
  302:           result = NULL;
  303:         }
  304:       else
  305:         {
  306:           /* Point the tree node at this new structure.  */
  307:           *found = known;
  308:           known->fct_name = fct_name;
  309: 
  310:           if (ni->library == NULL)
  311:             {
  312:               /* This service has not yet been used.  Fetch the service
  313:                  library for it, creating a new one if need be.  If there
  314:                  is no service table from the file, this static variable
  315:                  holds the head of the service_library list made from the
  316:                  default configuration.  */
  317:               static name_database default_table;
  318:               ni->library = nss_new_service (service_table ?: &default_table,
  319:                                              ni->name);
  320:               if (ni->library == NULL)
  321:                 {
  322:                   /* This only happens when out of memory.  */
  323:                   free (known);
  324:                   goto remove_from_tree;
  325:                 }
  326:             }
  327: 
  328: #if !defined DO_STATIC_NSS || defined SHARED
  329:           if (ni->library->lib_handle == NULL)
  330:             {
  331:               /* Load the shared library.  */
  332:               size_t shlen = (7 + strlen (ni->library->name) + 3
  333:                               + strlen (__nss_shlib_revision) + 1);
  334:               int saved_errno = errno;
  335:               char shlib_name[shlen];
  336: 
  337:               /* Construct shared object name.  */
  338:               __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
  339:                                                       "libnss_"),
  340:                                             ni->library->name),
  341:                                   ".so"),
  342:                         __nss_shlib_revision);
  343: 
  344:               ni->library->lib_handle = __libc_dlopen (shlib_name);
  345:               if (ni->library->lib_handle == NULL)
  346:                 {
  347:                   /* Failed to load the library.  */
  348:                   ni->library->lib_handle = (void *) -1l;
  349:                   __set_errno (saved_errno);
  350:                 }
  351:             }
  352: 
  353:           if (ni->library->lib_handle == (void *) -1l)
  354:             /* Library not found => function not found.  */
  355:             result = NULL;
  356:           else
  357:             {
  358:               /* Get the desired function.  */
  359:               size_t namlen = (5 + strlen (ni->library->name) + 1
  360:                                + strlen (fct_name) + 1);
  361:               char name[namlen];
  362: 
  363:               /* Construct the function name.  */
  364:               __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
  365:                                             ni->library->name),
  366:                                   "_"),
  367:                         fct_name);
  368: 
  369:               /* Look up the symbol.  */
  370:               result = __libc_dlsym (ni->library->lib_handle, name);
  371:             }
  372: #else
  373:           /* We can't get function address dynamically in static linking. */
  374:           {
  375: # define DEFINE_ENT(h,nm)                                                     \
  376:             { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },               \
  377:             { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },                   \
  378:             { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
  379: # define DEFINE_GET(h,nm)                                                     \
  380:             { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
  381: # define DEFINE_GETBY(h,nm,ky)                                                \
  382:             { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
  383:             static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
  384:               {
  385: # include "function.def"
  386:                 { NULL, NULL }
  387:               };
  388:             size_t namlen = (5 + strlen (ni->library->name) + 1
  389:                              + strlen (fct_name) + 1);
  390:             char name[namlen];
  391: 
  392:             /* Construct the function name.  */
  393:             __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
  394:                                 "_"),
  395:                       fct_name);
  396: 
  397:             result = NULL;
  398:             for (tp = &tbl[0]; tp->fname; tp++)
  399:               if (strcmp (tp->fname, name) == 0)
  400:                 {
  401:                   result = tp->fp;
  402:                   break;
  403:                 }
  404:           }
  405: #endif
  406: 
  407:           /* Remember function pointer for later calls.  Even if null, we
  408:              record it so a second try needn't search the library again.  */
  409:           known->fct_ptr = result;
  410:         }
  411:     }
  412: 
  413:   /* Remove the lock.  */
  414:   __libc_lock_unlock (lock);
  415: 
  416:   return result;
  417: }
  418: libc_hidden_def (__nss_lookup_function)
  419: 
  420: 
  421: static name_database *
  422: internal_function
  423: nss_parse_file (const char *fname)
  424: {
  425:   FILE *fp;
  426:   name_database *result;
  427:   name_database_entry *last;
  428:   char *line;
  429:   size_t len;
  430: 
  431:   /* Open the configuration file.  */
  432:   fp = fopen (fname, "rc");
  433:   if (fp == NULL)
  434:     return NULL;
  435: 
  436:   /* No threads use this stream.  */
  437:   __fsetlocking (fp, FSETLOCKING_BYCALLER);
  438: 
  439:   result = (name_database *) malloc (sizeof (name_database));
  440:   if (result == NULL)
  441:     return NULL;
  442: 
  443:   result->entry = NULL;
  444:   result->library = NULL;
  445:   last = NULL;
  446:   line = NULL;
  447:   len = 0;
  448:   do
  449:     {
  450:       name_database_entry *this;
  451:       ssize_t n;
  452: 
  453:       n = __getline (&line, &len, fp);
  454:       if (n < 0)
  455:         break;
  456:       if (line[n - 1] == '\n')
  457:         line[n - 1] = '\0';
  458: 
  459:       /* Because the file format does not know any form of quoting we
  460:          can search forward for the next '#' character and if found
  461:          make it terminating the line.  */
  462:       *__strchrnul (line, '#') = '\0';
  463: 
  464:       /* If the line is blank it is ignored.  */
  465:       if (line[0] == '\0')
  466:         continue;
  467: 
  468:       /* Each line completely specifies the actions for a database.  */
  469:       this = nss_getline (line);
  470:       if (this != NULL)
  471:         {
  472:           if (last != NULL)
  473:             last->next = this;
  474:           else
  475:             result->entry = this;
  476: 
  477:           last = this;
  478:         }
  479:     }
  480:   while (!feof_unlocked (fp));
  481: 
  482:   /* Free the buffer.  */
  483:   free (line);
  484:   /* Close configuration file.  */
  485:   fclose (fp);
  486: 
  487:   return result;
  488: }
  489: 
  490: 
  491: /* Read the source names:
  492:         `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
  493:    */
  494: static service_user *
  495: internal_function
  496: nss_parse_service_list (const char *line)
  497: {
  498:   service_user *result = NULL, **nextp = &result;
  499: 
  500:   while (1)
  501:     {
  502:       service_user *new_service;
  503:       const char *name;
  504: 
  505:       while (isspace (line[0]))
  506:         ++line;
  507:       if (line[0] == '\0')
  508:         /* No source specified.  */
  509:         return result;
  510: 
  511:       /* Read <source> identifier.  */
  512:       name = line;
  513:       while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
  514:         ++line;
  515:       if (name == line)
  516:         return result;
  517: 
  518: 
  519:       new_service = (service_user *) malloc (sizeof (service_user)
  520:                                              + (line - name + 1));
  521:       if (new_service == NULL)
  522:         return result;
  523: 
  524:       *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
  525: 
  526:       /* Set default actions.  */
  527:       new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
  528:       new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
  529:       new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
  530:       new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
  531:       new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
  532:       new_service->library = NULL;
  533:       new_service->known = NULL;
  534:       new_service->next = NULL;
  535: 
  536:       while (isspace (line[0]))
  537:         ++line;
  538: 
  539:       if (line[0] == '[')
  540:         {
  541:           /* Read criterions.  */
  542:           do
  543:             ++line;
  544:           while (line[0] != '\0' && isspace (line[0]));
  545: 
  546:           do
  547:             {
  548:               int not;
  549:               enum nss_status status;
  550:               lookup_actions action;
  551: 
  552:               /* Grok ! before name to mean all statii but that one.  */
  553:               not = line[0] == '!';
  554:               if (not)
  555:                 ++line;
  556: 
  557:               /* Read status name.  */
  558:               name = line;
  559:               while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
  560:                      && line[0] != ']')
  561:                 ++line;
  562: 
  563:               /* Compare with known statii.  */
  564:               if (line - name == 7)
  565:                 {
  566:                   if (__strncasecmp (name, "SUCCESS", 7) == 0)
  567:                     status = NSS_STATUS_SUCCESS;
  568:                   else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
  569:                     status = NSS_STATUS_UNAVAIL;
  570:                   else
  571:                     return result;
  572:                 }
  573:               else if (line - name == 8)
  574:                 {
  575:                   if (__strncasecmp (name, "NOTFOUND", 8) == 0)
  576:                     status = NSS_STATUS_NOTFOUND;
  577:                   else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
  578:                     status = NSS_STATUS_TRYAGAIN;
  579:                   else
  580:                     return result;
  581:                 }
  582:               else
  583:                 return result;
  584: 
  585:               while (isspace (line[0]))
  586:                 ++line;
  587:               if (line[0] !=