1 /* Copyright (c) 1998-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
18 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
38 #include <sys/socket.h>
48 #include "../nss/nsswitch.h"
49 #include <device-nrs.h>
51 # include <sys/inotify.h>
53 #include <kernel-features.h>
55 /* Get libc version number. */
58 #define PACKAGE _libc_intl_domainname
66 /* Running in background as daemon. */
68 /* Running in foreground but otherwise behave like a daemon,
69 i.e., detach from terminal and use syslog. This allows
70 better integration with services like systemd. */
72 /* Run in foreground in debug mode. */
76 static run_modes run_mode = RUN_DAEMONIZE;
78 static const char *conffile = _PATH_NSCDCONF;
82 uintptr_t pagesize_m1;
86 time_t restart_interval = RESTART_INTERVAL;
91 static int check_pid (const char *file);
92 static int write_pid (const char *file);
93 static int monitor_child (int fd);
95 /* Name and version of program. */
96 static void print_version (FILE *stream, struct argp_state *state);
97 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
99 /* Function to print some extra text in the help message. */
100 static char *more_help (int key, const char *text, void *input);
102 /* Definitions of arguments for argp functions. */
103 static const struct argp_option options[] =
105 { "config-file", 'f', N_("NAME"), 0,
106 N_("Read configuration data from NAME") },
107 { "debug", 'd', NULL, 0,
108 N_("Do not fork and display messages on the current tty") },
109 { "foreground", 'F', NULL, 0,
110 N_("Do not fork, but otherwise behave like a daemon") },
111 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
112 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
113 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
114 { "invalidate", 'i', N_("TABLE"), 0,
115 N_("Invalidate the specified cache") },
116 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
117 N_("Use separate cache for each user")},
118 { NULL, 0, NULL, 0, NULL }
121 /* Short description of program. */
122 static const char doc[] = N_("Name Service Cache Daemon.");
124 /* Prototype for option handler. */
125 static error_t parse_opt (int key, char *arg, struct argp_state *state);
127 /* Data structure to communicate with argp functions. */
128 static struct argp argp =
130 options, parse_opt, NULL, doc, NULL, more_help
133 /* True if only statistics are requested. */
134 static bool get_stats;
135 static int parent_fd = -1;
138 main (int argc, char **argv)
142 /* Set locale via LC_ALL. */
143 setlocale (LC_ALL, "");
144 /* Set the text message domain. */
145 textdomain (PACKAGE);
147 /* Determine if the kernel has SELinux support. */
148 nscd_selinux_enabled (&selinux_enabled);
150 /* Parse and process arguments. */
151 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
153 if (remaining != argc)
155 error (0, 0, gettext ("wrong number of arguments"));
156 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
160 /* Read the configuration file. */
161 if (nscd_parse_file (conffile, dbs) != 0)
162 /* We couldn't read the configuration file. We don't start the
164 error (EXIT_FAILURE, 0,
165 _("failure while reading configuration file; this is fatal"));
167 /* Do we only get statistics? */
169 /* Does not return. */
170 receive_print_stats ();
172 /* Check if we are already running. */
173 if (check_pid (_PATH_NSCDPID))
174 error (EXIT_FAILURE, 0, _("already running"));
176 /* Remember when we started. */
177 start_time = time (NULL);
179 /* Determine page size. */
180 pagesize_m1 = getpagesize () - 1;
182 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
187 /* Behave like a daemon. */
188 if (run_mode == RUN_DAEMONIZE)
193 error (EXIT_FAILURE, errno,
194 _("cannot create a pipe to talk to the child"));
198 error (EXIT_FAILURE, errno, _("cannot fork"));
201 /* The parent only reads from the child. */
203 exit (monitor_child (fd[0]));
207 /* The child only writes to the parent. */
213 int nullfd = open (_PATH_DEVNULL, O_RDWR);
218 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
219 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
220 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
224 /* It is the /dev/null special device alright. */
225 (void) dup2 (nullfd, STDIN_FILENO);
226 (void) dup2 (nullfd, STDOUT_FILENO);
227 (void) dup2 (nullfd, STDERR_FILENO);
234 /* Ugh, somebody is trying to play a trick on us. */
239 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
241 DIR *d = opendir ("/proc/self/fd");
244 struct dirent64 *dirent;
245 int dfdn = dirfd (d);
247 while ((dirent = readdir64 (d)) != NULL)
250 long int fdn = strtol (dirent->d_name, &endp, 10);
252 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd
260 for (i = min_close_fd; i < getdtablesize (); i++)
266 if (chdir ("/") != 0)
267 do_exit (EXIT_FAILURE, errno,
268 _("cannot change current working directory to \"/\""));
270 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
272 if (write_pid (_PATH_NSCDPID) < 0)
273 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
275 if (!init_logfile ())
276 dbg_log (_("Could not create log file"));
278 /* Ignore job control signals. */
279 signal (SIGTTOU, SIG_IGN);
280 signal (SIGTTIN, SIG_IGN);
281 signal (SIGTSTP, SIG_IGN);
284 /* In debug mode we are not paranoid. */
287 signal (SIGINT, termination_handler);
288 signal (SIGQUIT, termination_handler);
289 signal (SIGTERM, termination_handler);
290 signal (SIGPIPE, SIG_IGN);
292 /* Cleanup files created by a previous 'bind'. */
293 unlink (_PATH_NSCDSOCKET);
296 /* Use inotify to recognize changed files. */
297 inotify_fd = inotify_init1 (IN_NONBLOCK);
298 # ifndef __ASSUME_IN_NONBLOCK
299 if (inotify_fd == -1 && errno == ENOSYS)
301 inotify_fd = inotify_init ();
302 if (inotify_fd != -1)
303 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
309 /* Make sure we do not get recursive calls. */
310 __nss_disable_nscd (register_traced_file);
313 /* Init databases. */
316 /* Start the SELinux AVC. */
320 /* Handle incoming requests */
327 static void __attribute__ ((noreturn))
328 invalidate_db (const char *dbname)
330 int sock = nscd_open_socket ();
335 size_t dbname_len = strlen (dbname) + 1;
336 size_t reqlen = sizeof (request_header) + dbname_len;
341 } *reqdata = alloca (reqlen);
343 reqdata->req.key_len = dbname_len;
344 reqdata->req.version = NSCD_VERSION;
345 reqdata->req.type = INVALIDATE;
346 memcpy (reqdata->dbname, dbname, dbname_len);
348 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, reqdata, reqlen,
351 if (nbytes != reqlen)
355 error (EXIT_FAILURE, err, _("write incomplete"));
358 /* Wait for ack. Older nscd just closed the socket when
359 prune_cache finished, silently ignore that. */
361 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
362 if (nbytes != 0 && nbytes != sizeof (resp))
366 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
372 error (EXIT_FAILURE, resp, _("invalidation failed"));
377 static void __attribute__ ((noreturn))
380 int sock = nscd_open_socket ();
386 req.version = NSCD_VERSION;
390 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req, sizeof req,
393 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
396 /* Handle program arguments. */
398 parse_opt (int key, char *arg, struct argp_state *state)
404 run_mode = RUN_DEBUG;
408 run_mode = RUN_FOREGROUND;
417 error (4, 0, _("Only root is allowed to use this option!"));
428 /* Validate the database name. */
431 for (cnt = pwddb; cnt < lastdb; ++cnt)
432 if (strcmp (arg, dbnames[cnt]) == 0)
437 argp_error (state, _("'%s' is not a known database"), arg);
442 error (4, 0, _("Only root is allowed to use this option!"));
448 nthreads = atol (arg);
452 error (0, 0, _("secure services not implemented anymore"));
456 return ARGP_ERR_UNKNOWN;
462 /* Print bug-reporting information in the help message. */
464 more_help (int key, const char *text, void *input)
468 case ARGP_KEY_HELP_EXTRA:
470 /* We print some extra information. */
472 char *tables = xstrdup (dbnames[0]);
473 for (dbtype i = 1; i < lastdb; ++i)
476 if (asprintf (&more_tables, "%s %s", tables, dbnames[i]) < 0)
479 if (more_tables == NULL)
481 tables = more_tables;
485 if (asprintf (&tp, gettext ("\
489 For bug reporting instructions, please see:\n\
491 "), tables, REPORT_BUGS_TO) < 0)
501 return (char *) text;
504 /* Print the version information. */
506 print_version (FILE *stream, struct argp_state *state)
508 fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
509 fprintf (stream, gettext ("\
510 Copyright (C) %s Free Software Foundation, Inc.\n\
511 This is free software; see the source for copying conditions. There is NO\n\
512 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
514 fprintf (stream, gettext ("Written by %s.\n"),
515 "Thorsten Kukuk and Ulrich Drepper");
519 /* Create a socket connected to a name. */
521 nscd_open_socket (void)
523 struct sockaddr_un addr;
526 sock = socket (PF_UNIX, SOCK_STREAM, 0);
530 addr.sun_family = AF_UNIX;
531 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
532 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
533 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
545 termination_handler (int signum)
549 /* Clean up the file created by 'bind'. */
550 unlink (_PATH_NSCDSOCKET);
552 /* Clean up pid file. */
553 unlink (_PATH_NSCDPID);
555 // XXX Terminate threads.
557 /* Synchronize memory. */
558 for (int cnt = 0; cnt < lastdb; ++cnt)
560 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
563 /* Make sure nobody keeps using the database. */
564 dbs[cnt].head->timestamp = 0;
566 if (dbs[cnt].persistent)
568 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
571 _exit (EXIT_SUCCESS);
574 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
576 check_pid (const char *file)
580 fp = fopen (file, "r");
586 n = fscanf (fp, "%d", &pid);
589 /* If we cannot parse the file default to assuming nscd runs.
590 If the PID is alive, assume it is running. That all unless
591 the PID is the same as the current process' since tha latter
592 can mean we re-exec. */
593 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
600 /* Write the current process id to the file FILE.
601 Returns 0 if successful, -1 if not. */
603 write_pid (const char *file)
607 fp = fopen (file, "w");
611 fprintf (fp, "%d\n", getpid ());
613 int result = fflush (fp) || ferror (fp) ? -1 : 0;
621 monitor_child (int fd)
624 int ret = read (fd, &child_ret, sizeof (child_ret));
626 /* The child terminated with an error, either via exit or some other abnormal
627 method, like a segfault. */
628 if (ret <= 0 || child_ret != 0)
631 int err = wait (&status);
635 fprintf (stderr, _("'wait' failed\n"));
639 if (WIFEXITED (status))
641 child_ret = WEXITSTATUS (status);
642 fprintf (stderr, _("child exited with status %d\n"), child_ret);
644 if (WIFSIGNALED (status))
646 child_ret = WTERMSIG (status);
647 fprintf (stderr, _("child terminated by signal %d\n"), child_ret);
651 /* We have the child status, so exit with that code. */
658 do_exit (int child_ret, int errnum, const char *format, ...)
662 int ret __attribute__ ((unused));
663 ret = write (parent_fd, &child_ret, sizeof (child_ret));
664 assert (ret == sizeof (child_ret));
670 /* Emulate error() since we don't have a va_list variant for it. */
675 fprintf (stderr, "%s: ", program_invocation_name);
677 va_start (argp, format);
678 vfprintf (stderr, format, argp);
681 fprintf (stderr, ": %s\n", strerror (errnum));
690 notify_parent (int child_ret)
695 int ret __attribute__ ((unused));
696 ret = write (parent_fd, &child_ret, sizeof (child_ret));
697 assert (ret == sizeof (child_ret));