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

glibc/2.7/nscd/nscd.c

    1: /* Copyright (c) 1998-2006, 2007 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
    4: 
    5:    This program is free software; you can redistribute it and/or modify
    6:    it under the terms of the GNU General Public License as published
    7:    by the Free Software Foundation; version 2 of the License, or
    8:    (at your option) any later version.
    9: 
   10:    This program 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
   13:    GNU General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU General Public License
   16:    along with this program; if not, write to the Free Software Foundation,
   17:    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
   18: 
   19: /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts.  */
   20: 
   21: #include <argp.h>
   22: #include <assert.h>
   23: #include <dirent.h>
   24: #include <errno.h>
   25: #include <error.h>
   26: #include <fcntl.h>
   27: #include <libintl.h>
   28: #include <locale.h>
   29: #include <paths.h>
   30: #include <pthread.h>
   31: #include <signal.h>
   32: #include <stdbool.h>
   33: #include <stdio.h>
   34: #include <stdlib.h>
   35: #include <string.h>
   36: #include <syslog.h>
   37: #include <unistd.h>
   38: #include <sys/mman.h>
   39: #include <sys/socket.h>
   40: #include <sys/stat.h>
   41: #include <sys/uio.h>
   42: #include <sys/un.h>
   43: 
   44: #include "dbg_log.h"
   45: #include "nscd.h"
   46: #include "selinux.h"
   47: #include "../nss/nsswitch.h"
   48: #include <device-nrs.h>
   49: 
   50: /* Get libc version number.  */
   51: #include <version.h>
   52: 
   53: #define PACKAGE _libc_intl_domainname
   54: 
   55: /* Structure used by main() thread to keep track of the number of
   56:    active threads.  Used to limit how many threads it will create
   57:    and under a shutdown condition to wait till all in-progress
   58:    requests have finished before "turning off the lights".  */
   59: 
   60: typedef struct
   61: {
   62:   int             num_active;
   63:   pthread_cond_t  thread_exit_cv;
   64:   pthread_mutex_t mutex;
   65: } thread_info_t;
   66: 
   67: thread_info_t thread_info;
   68: 
   69: int do_shutdown;
   70: int disabled_passwd;
   71: int disabled_group;
   72: int go_background = 1;
   73: 
   74: static const char *conffile = _PATH_NSCDCONF;
   75: 
   76: time_t start_time;
   77: 
   78: uintptr_t pagesize_m1;
   79: 
   80: int paranoia;
   81: time_t restart_time;
   82: time_t restart_interval = RESTART_INTERVAL;
   83: const char *oldcwd;
   84: uid_t old_uid;
   85: gid_t old_gid;
   86: 
   87: static int check_pid (const char *file);
   88: static int write_pid (const char *file);
   89: 
   90: /* Name and version of program.  */
   91: static void print_version (FILE *stream, struct argp_state *state);
   92: void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
   93: 
   94: /* Definitions of arguments for argp functions.  */
   95: static const struct argp_option options[] =
   96: {
   97:   { "config-file", 'f', N_("NAME"), 0,
   98:     N_("Read configuration data from NAME") },
   99:   { "debug", 'd', NULL, 0,
  100:     N_("Do not fork and display messages on the current tty") },
  101:   { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
  102:   { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
  103:   { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
  104:   { "invalidate", 'i', N_("TABLE"), 0,
  105:     N_("Invalidate the specified cache") },
  106:   { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
  107:     N_("Use separate cache for each user")},
  108:   { NULL, 0, NULL, 0, NULL }
  109: };
  110: 
  111: /* Short description of program.  */
  112: static const char doc[] = N_("Name Service Cache Daemon.");
  113: 
  114: /* Prototype for option handler.  */
  115: static error_t parse_opt (int key, char *arg, struct argp_state *state);
  116: 
  117: /* Data structure to communicate with argp functions.  */
  118: static struct argp argp =
  119: {
  120:   options, parse_opt, NULL, doc,
  121: };
  122: 
  123: /* True if only statistics are requested.  */
  124: static bool get_stats;
  125: 
  126: int
  127: main (int argc, char **argv)
  128: {
  129:   int remaining;
  130: 
  131:   /* Set locale via LC_ALL.  */
  132:   setlocale (LC_ALL, "");
  133:   /* Set the text message domain.  */
  134:   textdomain (PACKAGE);
  135: 
  136:   /* Determine if the kernel has SELinux support.  */
  137:   nscd_selinux_enabled (&selinux_enabled);
  138: 
  139:   /* Parse and process arguments.  */
  140:   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
  141: 
  142:   if (remaining != argc)
  143:     {
  144:       error (0, 0, gettext ("wrong number of arguments"));
  145:       argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
  146:       exit (1);
  147:     }
  148: 
  149:   /* Read the configuration file.  */
  150:   if (nscd_parse_file (conffile, dbs) != 0)
  151:     /* We couldn't read the configuration file.  We don't start the
  152:        server.  */
  153:     error (EXIT_FAILURE, 0,
  154:            _("failure while reading configuration file; this is fatal"));
  155: 
  156:   /* Do we only get statistics?  */
  157:   if (get_stats)
  158:     /* Does not return.  */
  159:     receive_print_stats ();
  160: 
  161:   /* Check if we are already running. */
  162:   if (check_pid (_PATH_NSCDPID))
  163:     error (EXIT_FAILURE, 0, _("already running"));
  164: 
  165:   /* Remember when we started.  */
  166:   start_time = time (NULL);
  167: 
  168:   /* Determine page size.  */
  169:   pagesize_m1 = getpagesize () - 1;
  170: 
  171:   /* Behave like a daemon.  */
  172:   if (go_background)
  173:     {
  174:       int i;
  175: 
  176:       pid_t pid = fork ();
  177:       if (pid == -1)
  178:         error (EXIT_FAILURE, errno, _("cannot fork"));
  179:       if (pid != 0)
  180:         exit (0);
  181: 
  182:       int nullfd = open (_PATH_DEVNULL, O_RDWR);
  183:       if (nullfd != -1)
  184:         {
  185:           struct stat64 st;
  186: 
  187:           if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
  188: #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
  189:               && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
  190: #endif
  191:               )
  192:             {
  193:               /* It is the /dev/null special device alright.  */
  194:               (void) dup2 (nullfd, STDIN_FILENO);
  195:               (void) dup2 (nullfd, STDOUT_FILENO);
  196:               (void) dup2 (nullfd, STDERR_FILENO);
  197: 
  198:               if (nullfd > 2)
  199:                 close (nullfd);
  200:             }
  201:           else
  202:             {
  203:               /* Ugh, somebody is trying to play a trick on us.  */
  204:               close (nullfd);
  205:               nullfd = -1;
  206:             }
  207:         }
  208:       int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
  209: 
  210:       DIR *d = opendir ("/proc/self/fd");
  211:       if (d != NULL)
  212:         {
  213:           struct dirent64 *dirent;
  214:           int dfdn = dirfd (d);
  215: 
  216:           while ((dirent = readdir64 (d)) != NULL)
  217:             {
  218:               char *endp;
  219:               long int fdn = strtol (dirent->d_name, &endp, 10);
  220: 
  221:               if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
  222:                 close ((int) fdn);
  223:             }
  224: 
  225:           closedir (d);
  226:         }
  227:       else
  228:         for (i = min_close_fd; i < getdtablesize (); i++)
  229:           close (i);
  230: 
  231:       pid = fork ();
  232:       if (pid == -1)
  233:         error (EXIT_FAILURE, errno, _("cannot fork"));
  234:       if (pid != 0)
  235:         exit (0);
  236: 
  237:       setsid ();
  238: 
  239:       if (chdir ("/") != 0)
  240:         error (EXIT_FAILURE, errno,
  241:                _("cannot change current working directory to \"/\""));
  242: 
  243:       openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
  244: 
  245:       if (write_pid (_PATH_NSCDPID) < 0)
  246:         dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
  247: 
  248:       if (!init_logfile ())
  249:         dbg_log (_("Could not create log file"));
  250: 
  251:       /* Ignore job control signals.  */
  252:       signal (SIGTTOU, SIG_IGN);
  253:       signal (SIGTTIN, SIG_IGN);
  254:       signal (SIGTSTP, SIG_IGN);
  255:     }
  256:   else
  257:     /* In foreground mode we are not paranoid.  */
  258:     paranoia = 0;
  259: 
  260:   /* Start the SELinux AVC.  */
  261:   if (selinux_enabled)
  262:     nscd_avc_init ();
  263: 
  264:   signal (SIGINT, termination_handler);
  265:   signal (SIGQUIT, termination_handler);
  266:   signal (SIGTERM, termination_handler);
  267:   signal (SIGPIPE, SIG_IGN);
  268: 
  269:   /* Cleanup files created by a previous 'bind'.  */
  270:   unlink (_PATH_NSCDSOCKET);
  271: 
  272:   /* Make sure we do not get recursive calls.  */
  273:   __nss_disable_nscd ();
  274: 
  275:   /* Init databases.  */
  276:   nscd_init ();
  277: 
  278:   /* Handle incoming requests */
  279:   start_threads ();
  280: 
  281:   return 0;
  282: }
  283: 
  284: 
  285: /* Handle program arguments.  */
  286: static error_t
  287: parse_opt (int key, char *arg, struct argp_state *state)
  288: {
  289:   switch (key)
  290:     {
  291:     case 'd':
  292:       ++debug_level;
  293:       go_background = 0;
  294:       break;
  295: 
  296:     case 'f':
  297:       conffile = arg;
  298:       break;
  299: 
  300:     case 'K':
  301:       if (getuid () != 0)
  302:         error (4, 0, _("Only root is allowed to use this option!"));
  303:       {
  304:         int sock = nscd_open_socket ();
  305: 
  306:         if (sock == -1)
  307:           exit (EXIT_FAILURE);
  308: 
  309:         request_header req;
  310:         req.version = NSCD_VERSION;
  311:         req.type = SHUTDOWN;
  312:         req.key_len = 0;
  313: 
  314:         ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
  315:                                                    sizeof (request_header),
  316:                                                    MSG_NOSIGNAL));
  317:         close (sock);
  318:         exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
  319:       }
  320: 
  321:     case 'g':
  322:       get_stats = true;
  323:       break;
  324: 
  325:     case 'i':
  326:       if (getuid () != 0)
  327:         error (4, 0, _("Only root is allowed to use this option!"));
  328:       else
  329:         {
  330:           int sock = nscd_open_socket ();
  331: 
  332:           if (sock == -1)
  333:             exit (EXIT_FAILURE);
  334: 
  335:           dbtype cnt;
  336:           for (cnt = pwddb; cnt < lastdb; ++cnt)
  337:             if (strcmp (arg, dbnames[cnt]) == 0)
  338:               break;
  339: 
  340:           if (cnt == lastdb)
  341:             return ARGP_ERR_UNKNOWN;
  342: 
  343:           size_t arg_len = strlen (arg) + 1;
  344:           struct
  345:           {
  346:             request_header req;
  347:             char arg[arg_len];
  348:           } reqdata;
  349: 
  350:           reqdata.req.key_len = strlen (arg) + 1;
  351:           reqdata.req.version = NSCD_VERSION;
  352:           reqdata.req.type = INVALIDATE;
  353:           memcpy (reqdata.arg, arg, arg_len);
  354: 
  355:           ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
  356:                                                      sizeof (request_header)
  357:                                                      + arg_len,
  358:                                                      MSG_NOSIGNAL));
  359: 
  360:           if (nbytes != sizeof (request_header) + arg_len)
  361:             {
  362:               int err = errno;
  363:               close (sock);
  364:               error (EXIT_FAILURE, err, _("write incomplete"));
  365:             }
  366: 
  367:           /* Wait for ack.  Older nscd just closed the socket when
  368:              prune_cache finished, silently ignore that.  */
  369:           int32_t resp = 0;
  370:           nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
  371:           if (nbytes != 0 && nbytes != sizeof (resp))
  372:             {
  373:               int err = errno;
  374:               close (sock);
  375:               error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
  376:             }
  377: 
  378:           close (sock);
  379: 
  380:           if (resp != 0)
  381:             error (EXIT_FAILURE, resp, _("invalidation failed"));
  382: 
  383:           exit (0);
  384:         }
  385: 
  386:     case 't':
  387:       nthreads = atol (arg);
  388:       break;
  389: 
  390:     case 'S':
  391:       error (0, 0, _("secure services not implemented anymore"));
  392:       break;
  393: 
  394:     default:
  395:       return ARGP_ERR_UNKNOWN;
  396:     }
  397: 
  398:   return 0;
  399: }
  400: 
  401: /* Print the version information.  */
  402: static void
  403: print_version (FILE *stream, struct argp_state *state)
  404: {
  405:   fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
  406:   fprintf (stream, gettext ("\
  407: Copyright (C) %s Free Software Foundation, Inc.\n\
  408: This is free software; see the source for copying conditions.  There is NO\n\
  409: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
  410: "), "2007");
  411:   fprintf (stream, gettext ("Written by %s.\n"),
  412:            "Thorsten Kukuk and Ulrich Drepper");
  413: }
  414: 
  415: 
  416: /* Create a socket connected to a name.  */
  417: int
  418: nscd_open_socket (void)
  419: {
  420:   struct sockaddr_un addr;
  421:   int sock;
  422: 
  423:   sock = socket (PF_UNIX, SOCK_STREAM, 0);
  424:   if (sock < 0)
  425:     return -1;
  426: 
  427:   addr.sun_family = AF_UNIX;
  428:   assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
  429:   strcpy (addr.sun_path, _PATH_NSCDSOCKET);
  430:   if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
  431:     {
  432:       close (sock);
  433:       return -1;
  434:     }
  435: 
  436:   return sock;
  437: }
  438: 
  439: 
  440: /* Cleanup.  */
  441: void
  442: termination_handler (int signum)
  443: {
  444:   close_sockets ();
  445: 
  446:   /* Clean up the file created by 'bind'.  */
  447:   unlink (_PATH_NSCDSOCKET);
  448: 
  449:   /* Clean up pid file.  */
  450:   unlink (_PATH_NSCDPID);
  451: 
  452:   // XXX Terminate threads.
  453: 
  454:   /* Synchronize memory.  */
  455:   for (int cnt = 0; cnt < lastdb; ++cnt)
  456:     {
  457:       if (!dbs[cnt].enabled)
  458:         continue;
  459: 
  460:       /* Make sure nobody keeps using the database.  */
  461:       dbs[cnt].head->timestamp = 0;
  462: 
  463:       if (dbs[cnt].persistent)
  464:         // XXX async OK?
  465:         msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
  466:     }
  467: 
  468:   /* Shutdown the SELinux AVC.  */
  469:   if (selinux_enabled)
  470:     nscd_avc_destroy ();
  471: 
  472:   _exit (EXIT_SUCCESS);
  473: }
  474: 
  475: /* Returns 1 if the process in pid file FILE is running, 0 if not.  */
  476: static int
  477: check_pid (const char *file)
  478: {
  479:   FILE *fp;
  480: 
  481:   fp = fopen (file, "r");
  482:   if (fp)
  483:     {
  484:       pid_t pid;
  485:       int n;
  486: 
  487:       n = fscanf (fp, "%d", &pid);
  488:       fclose (fp);
  489: 
  490:       /* If we cannot parse the file default to assuming nscd runs.
  491:          If the PID is alive, assume it is running.  That all unless
  492:          the PID is the same as the current process' since tha latter
  493:          can mean we re-exec.  */
  494:       if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
  495:         return 1;
  496:     }
  497: 
  498:   return 0;
  499: }
  500: 
  501: /* Write the current process id to the file FILE.
  502:    Returns 0 if successful, -1 if not.  */
  503: static int
  504: write_pid (const char *file)
  505: {
  506:   FILE *fp;
  507: 
  508:   fp = fopen (file, "w");
  509:   if (fp == NULL)
  510:     return -1;
  511: 
  512:   fprintf (fp, "%d\n", getpid ());
  513: 
  514:   int result = fflush (fp) || ferror (fp) ? -1 : 0;
  515: 
  516:   fclose (fp);
  517: 
  518:   return result;
  519: }
1
Syntax (Markdown)