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

glibc/2.7/nscd/connections.c

    1: /* Inner loops of cache daemon.
    2:    Copyright (C) 1998-2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
    5: 
    6:    This program is free software; you can redistribute it and/or modify
    7:    it under the terms of the GNU General Public License as published
    8:    by the Free Software Foundation; version 2 of the License, or
    9:    (at your option) any later version.
   10: 
   11:    This program is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:    GNU General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU General Public License
   17:    along with this program; if not, write to the Free Software Foundation,
   18:    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
   19: 
   20: #include <alloca.h>
   21: #include <assert.h>
   22: #include <atomic.h>
   23: #include <error.h>
   24: #include <errno.h>
   25: #include <fcntl.h>
   26: #include <grp.h>
   27: #include <libintl.h>
   28: #include <pthread.h>
   29: #include <pwd.h>
   30: #include <resolv.h>
   31: #include <stdio.h>
   32: #include <stdlib.h>
   33: #include <unistd.h>
   34: #include <arpa/inet.h>
   35: #ifdef HAVE_EPOLL
   36: # include <sys/epoll.h>
   37: #endif
   38: #include <sys/mman.h>
   39: #include <sys/param.h>
   40: #include <sys/poll.h>
   41: #ifdef HAVE_SENDFILE
   42: # include <sys/sendfile.h>
   43: #endif
   44: #include <sys/socket.h>
   45: #include <sys/stat.h>
   46: #include <sys/un.h>
   47: 
   48: #include "nscd.h"
   49: #include "dbg_log.h"
   50: #include "selinux.h"
   51: #ifdef HAVE_SENDFILE
   52: # include <kernel-features.h>
   53: #endif
   54: 
   55: 
   56: /* Wrapper functions with error checking for standard functions.  */
   57: extern void *xmalloc (size_t n);
   58: extern void *xcalloc (size_t n, size_t s);
   59: extern void *xrealloc (void *o, size_t n);
   60: 
   61: /* Support to run nscd as an unprivileged user */
   62: const char *server_user;
   63: static uid_t server_uid;
   64: static gid_t server_gid;
   65: const char *stat_user;
   66: uid_t stat_uid;
   67: static gid_t *server_groups;
   68: #ifndef NGROUPS
   69: # define NGROUPS 32
   70: #endif
   71: static int server_ngroups;
   72: 
   73: static pthread_attr_t attr;
   74: 
   75: static void begin_drop_privileges (void);
   76: static void finish_drop_privileges (void);
   77: 
   78: /* Map request type to a string.  */
   79: const char *const serv2str[LASTREQ] =
   80: {
   81:   [GETPWBYNAME] = "GETPWBYNAME",
   82:   [GETPWBYUID] = "GETPWBYUID",
   83:   [GETGRBYNAME] = "GETGRBYNAME",
   84:   [GETGRBYGID] = "GETGRBYGID",
   85:   [GETHOSTBYNAME] = "GETHOSTBYNAME",
   86:   [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
   87:   [GETHOSTBYADDR] = "GETHOSTBYADDR",
   88:   [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
   89:   [SHUTDOWN] = "SHUTDOWN",
   90:   [GETSTAT] = "GETSTAT",
   91:   [INVALIDATE] = "INVALIDATE",
   92:   [GETFDPW] = "GETFDPW",
   93:   [GETFDGR] = "GETFDGR",
   94:   [GETFDHST] = "GETFDHST",
   95:   [GETAI] = "GETAI",
   96:   [INITGROUPS] = "INITGROUPS",
   97:   [GETSERVBYNAME] = "GETSERVBYNAME",
   98:   [GETSERVBYPORT] = "GETSERVBYPORT",
   99:   [GETFDSERV] = "GETFDSERV"
  100: };
  101: 
  102: /* The control data structures for the services.  */
  103: struct database_dyn dbs[lastdb] =
  104: {
  105:   [pwddb] = {
  106:     .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
  107:     .prunelock = PTHREAD_MUTEX_INITIALIZER,
  108:     .enabled = 0,
  109:     .check_file = 1,
  110:     .persistent = 0,
  111:     .propagate = 1,
  112:     .shared = 0,
  113:     .max_db_size = DEFAULT_MAX_DB_SIZE,
  114:     .reset_res = 0,
  115:     .filename = "/etc/passwd",
  116:     .db_filename = _PATH_NSCD_PASSWD_DB,
  117:     .disabled_iov = &pwd_iov_disabled,
  118:     .postimeout = 3600,
  119:     .negtimeout = 20,
  120:     .wr_fd = -1,
  121:     .ro_fd = -1,
  122:     .mmap_used = false
  123:   },
  124:   [grpdb] = {
  125:     .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
  126:     .prunelock = PTHREAD_MUTEX_INITIALIZER,
  127:     .enabled = 0,
  128:     .check_file = 1,
  129:     .persistent = 0,
  130:     .propagate = 1,
  131:     .shared = 0,
  132:     .max_db_size = DEFAULT_MAX_DB_SIZE,
  133:     .reset_res = 0,
  134:     .filename = "/etc/group",
  135:     .db_filename = _PATH_NSCD_GROUP_DB,
  136:     .disabled_iov = &grp_iov_disabled,
  137:     .postimeout = 3600,
  138:     .negtimeout = 60,
  139:     .wr_fd = -1,
  140:     .ro_fd = -1,
  141:     .mmap_used = false
  142:   },
  143:   [hstdb] = {
  144:     .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
  145:     .prunelock = PTHREAD_MUTEX_INITIALIZER,
  146:     .enabled = 0,
  147:     .check_file = 1,
  148:     .persistent = 0,
  149:     .propagate = 0,             /* Not used.  */
  150:     .shared = 0,
  151:     .max_db_size = DEFAULT_MAX_DB_SIZE,
  152:     .reset_res = 1,
  153:     .filename = "/etc/hosts",
  154:     .db_filename = _PATH_NSCD_HOSTS_DB,
  155:     .disabled_iov = &hst_iov_disabled,
  156:     .postimeout = 3600,
  157:     .negtimeout = 20,
  158:     .wr_fd = -1,
  159:     .ro_fd = -1,
  160:     .mmap_used = false
  161:   },
  162:   [servdb] = {
  163:     .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
  164:     .prunelock = PTHREAD_MUTEX_INITIALIZER,
  165:     .enabled = 0,
  166:     .check_file = 1,
  167:     .persistent = 0,
  168:     .propagate = 0,             /* Not used.  */
  169:     .shared = 0,
  170:     .max_db_size = DEFAULT_MAX_DB_SIZE,
  171:     .reset_res = 0,
  172:     .filename = "/etc/services",
  173:     .db_filename = _PATH_NSCD_SERVICES_DB,
  174:     .disabled_iov = &serv_iov_disabled,
  175:     .postimeout = 28800,
  176:     .negtimeout = 20,
  177:     .wr_fd = -1,
  178:     .ro_fd = -1,
  179:     .mmap_used = false
  180:   }
  181: };
  182: 
  183: 
  184: /* Mapping of request type to database.  */
  185: static struct
  186: {
  187:   bool data_request;
  188:   struct database_dyn *db;
  189: } const reqinfo[LASTREQ] =
  190: {
  191:   [GETPWBYNAME] = { true, &dbs[pwddb] },
  192:   [GETPWBYUID] = { true, &dbs[pwddb] },
  193:   [GETGRBYNAME] = { true, &dbs[grpdb] },
  194:   [GETGRBYGID] = { true, &dbs[grpdb] },
  195:   [GETHOSTBYNAME] = { true, &dbs[hstdb] },
  196:   [GETHOSTBYNAMEv6] = { true, &dbs[hstdb] },
  197:   [GETHOSTBYADDR] = { true, &dbs[hstdb] },
  198:   [GETHOSTBYADDRv6] = { true, &dbs[hstdb] },
  199:   [SHUTDOWN] = { false, NULL },
  200:   [GETSTAT] = { false, NULL },
  201:   [SHUTDOWN] = { false, NULL },
  202:   [GETFDPW] = { false, &dbs[pwddb] },
  203:   [GETFDGR] = { false, &dbs[grpdb] },
  204:   [GETFDHST] = { false, &dbs[hstdb] },
  205:   [GETAI] = { true, &dbs[hstdb] },
  206:   [INITGROUPS] = { true, &dbs[grpdb] },
  207:   [GETSERVBYNAME] = { true, &dbs[servdb] },
  208:   [GETSERVBYPORT] = { true, &dbs[servdb] },
  209:   [GETFDSERV] = { false, &dbs[servdb] }
  210: };
  211: 
  212: 
  213: /* Number of seconds between two cache pruning runs.  */
  214: #define CACHE_PRUNE_INTERVAL    15
  215: 
  216: 
  217: /* Initial number of threads to use.  */
  218: int nthreads = -1;
  219: /* Maximum number of threads to use.  */
  220: int max_nthreads = 32;
  221: 
  222: /* Socket for incoming connections.  */
  223: static int sock;
  224: 
  225: /* Number of times clients had to wait.  */
  226: unsigned long int client_queued;
  227: 
  228: 
  229: ssize_t
  230: writeall (int fd, const void *buf, size_t len)
  231: {
  232:   size_t n = len;
  233:   ssize_t ret;
  234:   do
  235:     {
  236:       ret = TEMP_FAILURE_RETRY (send (fd, buf, n, MSG_NOSIGNAL));
  237:       if (ret <= 0)
  238:         break;
  239:       buf = (const char *) buf + ret;
  240:       n -= ret;
  241:     }
  242:   while (n > 0);
  243:   return ret < 0 ? ret : len - n;
  244: }
  245: 
  246: 
  247: #ifdef HAVE_SENDFILE
  248: ssize_t
  249: sendfileall (int tofd, int fromfd, off_t off, size_t len)
  250: {
  251:   ssize_t n = len;
  252:   ssize_t ret;
  253: 
  254:   do
  255:     {
  256:       ret = TEMP_FAILURE_RETRY (sendfile (tofd, fromfd, &off, n));
  257:       if (ret <= 0)
  258:         break;
  259:       n -= ret;
  260:     }
  261:   while (n > 0);
  262:   return ret < 0 ? ret : len - n;
  263: }
  264: #endif
  265: 
  266: 
  267: enum usekey
  268:   {
  269:     use_not = 0,
  270:     /* The following three are not really used, they are symbolic constants.  */
  271:     use_first = 16,
  272:     use_begin = 32,
  273:     use_end = 64,
  274: 
  275:     use_he = 1,
  276:     use_he_begin = use_he | use_begin,
  277:     use_he_end = use_he | use_end,
  278: #if SEPARATE_KEY
  279:     use_key = 2,
  280:     use_key_begin = use_key | use_begin,
  281:     use_key_end = use_key | use_end,
  282:     use_key_first = use_key_begin | use_first,
  283: #endif
  284:     use_data = 3,
  285:     use_data_begin = use_data | use_begin,
  286:     use_data_end = use_data | use_end,
  287:     use_data_first = use_data_begin | use_first
  288:   };
  289: 
  290: 
  291: static int
  292: check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
  293:            enum usekey use, ref_t start, size_t len)
  294: {
  295:   assert (len >= 2);
  296: 
  297:   if (start > first_free || start + len > first_free
  298:       || (start & BLOCK_ALIGN_M1))
  299:     return 0;
  300: 
  301:   if (usemap[start] == use_not)
  302:     {
  303:       /* Add the start marker.  */
  304:       usemap[start] = use | use_begin;
  305:       use &= ~use_first;
  306: 
  307:       while (--len > 0)
  308:         if (usemap[++start] != use_not)
  309:           return 0;
  310:         else
  311:           usemap[start] = use;
  312: 
  313:       /* Add the end marker.  */
  314:       usemap[start] = use | use_end;
  315:     }
  316:   else if ((usemap[start] & ~use_first) == ((use | use_begin) & ~use_first))
  317:     {
  318:       /* Hash entries can't be shared.  */
  319:       if (use == use_he)
  320:         return 0;
  321: 
  322:       usemap[start] |= (use & use_first);
  323:       use &= ~use_first;
  324: 
  325:       while (--len > 1)
  326:         if (usemap[++start] != use)
  327:           return 0;
  328: 
  329:       if (usemap[++start] != (use | use_end))
  330:         return 0;
  331:     }
  332:   else
  333:     /* Points to a wrong object or somewhere in the middle.  */
  334:     return 0;
  335: 
  336:   return 1;
  337: }
  338: 
  339: 
  340: /* Verify data in persistent database.  */
  341: static int
  342: verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
  343: {
  344:   assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb);
  345: 
  346:   time_t now = time (NULL);
  347: 
  348:   struct database_pers_head *head = mem;
  349:   struct database_pers_head head_copy = *head;
  350: 
  351:   /* Check that the header that was read matches the head in the database.  */
  352:   if (readhead != NULL && memcmp (head, readhead, sizeof (*head)) != 0)
  353:     return 0;
  354: 
  355:   /* First some easy tests: make sure the database header is sane.  */
  356:   if (head->version != DB_VERSION
  357:       || head->header_size != sizeof (*head)
  358:       /* We allow a timestamp to be one hour ahead of the current time.
  359:          This should cover daylight saving time changes.  */
  360:       || head->timestamp > now + 60 * 60 + 60
  361:       || (head->gc_cycle & 1)
  362:       || (size_t) head->module > INT32_MAX / sizeof (ref_t)
  363:       || (size_t) head->data_size > INT32_MAX - head->module * sizeof (ref_t)
  364:       || head->first_free < 0
  365:       || head->first_free > head->data_size
  366:       || (head->first_free & BLOCK_ALIGN_M1) != 0
  367:       || head->maxnentries < 0
  368:       || head->maxnsearched < 0)
  369:     return 0;
  370: 
  371:   uint8_t *usemap = calloc (head->first_free, 1);
  372:   if (usemap == NULL)
  373:     return 0;
  374: 
  375:   const char *data = (char *) &head->array[roundup (head->module,
  376:                                                     ALIGN / sizeof (ref_t))];
  377: 
  378:   nscd_ssize_t he_cnt = 0;
  379:   for (nscd_ssize_t cnt = 0; cnt < head->module; ++cnt)
  380:     {
  381:       ref_t trail = head->array[cnt];
  382:       ref_t work = trail;
  383:       int tick = 0;
  384: 
  385:       while (work != ENDREF)
  386:         {
  387:           if (! check_use (data, head->first_free, usemap, use_he, work,
  388:                            sizeof (struct hashentry)))
  389:             goto fail;
  390: 
  391:           /* Now we know we can dereference the record.  */
  392:           struct hashentry *here = (struct hashentry *) (data + work);
  393: 
  394:           ++he_cnt;
  395: 
  396:           /* Make sure the record is for this type of service.  */
  397:           if (here->type >= LASTREQ
  398:               || reqinfo[here->type].db != &dbs[dbnr])
  399:             goto fail;
  400: 
  401:           /* Validate boolean field value.  */
  402:           if (here->first != false && here->first != true)
  403:             goto fail;
  404: 
  405:           if (here->len < 0)
  406:             goto fail;
  407: 
  408:           /* Now the data.  */
  409:           if (here->packet < 0
  410:               || here->packet > head->first_free
  411:               || here->packet + sizeof (struct datahead) > head->first_free)
  412:             goto fail;
  413: 
  414:           struct datahead *dh = (struct datahead *) (data + here->packet);
  415: 
  416:           if (! check_use (data, head->first_free, usemap,
  417:                            use_data | (here->first ? use_first : 0),
  418:                            here->packet, dh->allocsize))
  419:             goto fail;
  420: 
  421:           if (dh->allocsize < sizeof (struct datahead)
  422:               || dh->recsize > dh->allocsize
  423:               || (dh->notfound != false && dh->notfound != true)
  424:               || (dh->usable != false && dh->usable != true))
  425:             goto fail;
  426: 
  427:           if (here->key < here->packet + sizeof (struct datahead)
  428:               || here->key > here->packet + dh->allocsize
  429:               || here->key + here->len > here->packet + dh->allocsize)
  430:             {
  431: #if SEPARATE_KEY
  432:               /* If keys can appear outside of data, this should be done
  433:                  instead.  But gc doesn't mark the data in that case.  */
  434:               if (! check_use (data, head->first_free, usemap,
  435:                                use_key | (here->first ? use_first : 0),
  436:                                here->key, here->len))
  437: #endif
  438:                 goto fail;
  439:             }
  440: 
  441:           work = here->next;
  442: 
  443:           if (work == trail)
  444:             /* A circular list, this must not happen.  */
  445:             goto fail;
  446:           if (tick)
  447:             trail = ((struct hashentry *) (data + trail))->next;
  448:           tick = 1 - tick;
  449:         }
  450:     }
  451: 
  452:   if (he_cnt != head->nentries)
  453:     goto fail;
  454: 
  455:   /* See if all data and keys had at least one reference from
  456:      he->first == true hashentry.  */
  457:   for (ref_t idx = 0; idx < head->first_free; ++idx)
  458:     {
  459: #if SEPARATE_KEY
  460:       if (usemap[idx] == use_key_begin)
  461:         goto fail;
  462: #endif
  463:       if (usemap[idx] == use_data_begin)
  464:         goto fail;
  465:     }
  466: 
  467:   /* Finally, make sure the database hasn't changed since the first test.  */
  468:   if (memcmp (mem, &head_copy, sizeof (*head)) != 0)
  469:     goto fail;
  470: 
  471:   free (usemap);
  472:   return 1;
  473: 
  474: fail:
  475:   free (usemap);
  476:   return 0;
  477: }
  478: 
  479: 
  480: #ifdef O_CLOEXEC
  481: # define EXTRA_O_FLAGS O_CLOEXEC
  482: #else
  483: # define EXTRA_O_FLAGS 0
  484: #endif
  485: 
  486: 
  487: /* Initialize database information structures.  */
  488: void
  489: nscd_init (void)
  490: {
  491:   /* Look up unprivileged uid/gid/groups before we start listening on the
  492:      socket  */
  493:   if (server_user != NULL)
  494:     begin_drop_privileges ();
  495: 
  496:   if (nthreads == -1)
  497:     /* No configuration for this value, assume a default.  */
  498:     nthreads = 2 * lastdb;
  499: 
  500:   for (size_t cnt = 0; cnt < lastdb; ++cnt)
  501:     if (dbs[cnt].enabled)
  502:       {
  503:         pthread_rwlock_init (&dbs[cnt].lock, NULL);
  504:         pthread_mutex_init (&dbs[cnt].memlock, NULL);
  505: 
  506:         if (dbs[cnt].persistent)
  507:           {
  508:             /* Try to open the appropriate file on disk.  */
  509:             int fd = open (dbs[cnt].db_filename, O_RDWR | EXTRA_O_FLAGS);
  510:             if (fd != -1)
  511:               {
  512:                 struct stat64 st;
  513:                 void *mem;
  514:                 size_t total;
  515:                 struct database_pers_head head;
  516:                 ssize_t n = TEMP_FAILURE_RETRY (read (fd, &head,
  517:                                                       sizeof (head)));
  518:                 if (n != sizeof (head) || fstat64 (fd, &st) != 0)
  519:                   {
  520:                   fail_db:
  521:                     dbg_log (_("invalid persistent database file \"%s\": %s"),
  522:                              dbs[cnt].db_filename, strerror (errno));
  523:                     unlink (dbs[cnt].db_filename);
  524:                   }
  525:                 else if (head.module == 0 && head.data_size == 0)
  526:                   {
  527:                     /* The file has been created, but the head has not been
  528:                        initialized yet.  Remove the old file.  */
  529:                     unlink (dbs[cnt].db_filename);
  530:                   }
  531:                 else if (head.header_size != (int) sizeof (head))
  532:                   {
  533:                     dbg_log (_("invalid persistent database file \"%s\": %s"),
  534:                              dbs[cnt].db_filename,
  535:                              _("header size does not match"));
  536:                     unlink (dbs[cnt].db_filename);
  537:                   }
  538:                 else if ((total = (sizeof (head)
  539:                                    + roundup (head.module * sizeof (ref_t),
  540:                                               ALIGN)
  541:                                    + head.data_size))
  542:                          > st.st_size
  543:                          || total < sizeof (head))
  544:                   {
  545:                     dbg_log (_("invalid persistent database file \"%s\": %s"),
  546:                              dbs[cnt].db_filename,
  547:                              _("file size does not match"));
  548:                     unlink (dbs[cnt].db_filename);
  549:                   }
  550:                 /* Note we map with the maximum size allowed for the
  551:                    database.  This is likely much larger than the
  552:                    actual file size.  This is OK on most OSes since
  553:                    extensions of the underlying file will
  554:                    automatically translate more pages available for
  555:                    memory access.  */
  556:                 else if ((mem = mmap (NULL, dbs[cnt].max_db_size,
  557:                                       PROT_READ | PROT_WRITE,
  558:                                       MAP_SHARED,